简体   繁体   中英

Does MySQL different engine types (InnoDB and Aria) affect on query with large amount of LEFT JOIN?

I have one heavy MySQL query with 12 LEFT JOIN and noticed that some of tables have InnoDB engine and some Aria . I've attached EXPLAIN of this query and pointed engine types at image with corresponding letters I and A .

Does fact of different engines affects on query speed and how seriously? Does changing of engines types helps to optimize query execution?

What else I could do to optimize this query?

在此处输入图像描述

Query (if needed)

SELECT user.id, user.first_name, user.last_name, user.birthday, user.email, user.phone, user.address_id, 
        user.alt_address_id, user.type, user.level_id, user_level.level, user.consecutive_orders, user.orders_count, 
        user.code_id, user.period, user.preferences, user.is_pick_up, user.pickup_address_id, user.is_active, 
        user.first_delivery_date, user.change_delivery_date, user.eway_id, user.date_created, 
        user.rest_referral_discount as `rest_referral_discount`, user.rest_code_discount as `rest_code_discount`, 
        user.rest_code_box_discount as `rest_code_box_discount`, user.rest_code_mp_discount as `rest_code_mp_discount`, 
        user.rest_code_tup_discount as `rest_code_tup_discount`, user.nf_pantry_list, user.nf_next_weeks_menu, 
        user.nf_paused_reminder, user.nf_welcome, user.nf_expected_delivery_time, 
        user.nf_delivery, address_pickup.address as `pickup_address`, address.address, address.unit, 
        address.instructions, location.id location_id, location.postcode, location.suburb, 
        location_state.code state_code, delivery_area.delivery_area_window_id delivery_area_window_id, 
        delivery_area_by_location.fee delivery_fee_value, delivery_area_window.day delivery_day, 
        delivery_area_window.day_name_full delivery_day_name_full, delivery_area_window.window delivery_window, 
        user.delivery_area_id, user.alt_delivery_area_id, if (user.is_pick_up, 0, delivery_area.fee) delivery_fee, 
        if (user.type = 1 || user.type = 2, 5, 0) ondemand_fee, code.code code_name, code.amount code_amount, 
        code.value code_value, code.is_permanent is_code_permanent, code.repeat code_repeat, code.times code_times, 
        code.apply_to code_apply_to, code.valid_from code_valid_from, code.valid_until code_valid_until, 
        if (code_used.count > 0, 1, 0) is_code_used, if (code_used.count > 0, code_used.count, 0) code_used_count, 
        if (user.is_pick_up, IFNULL(delivery_area_by_location.topup_available, 0), IFNULL(delivery_area.topup_available, 0)) topup_available,
        
        (SELECT `order`.`id` FROM `order` LEFT JOIN `gift` ON gift.order_id = order.id 
        WHERE (`order`.`delivery_date` BETWEEN '2021-02-07' and '2021-02-13') and (user.id = order.user_id) and (`gift`.`id` IS NULL) 
        and (`order`.`status` = 10) ORDER BY `order`.`date_created` DESC LIMIT 1) as `order_id`,
         
        (SELECT `order`.`delivery_date` FROM `order` 
        LEFT JOIN `gift` 
            ON gift.order_id = order.id 
        WHERE (user.id = order.user_id) and (`gift`.`id` IS NULL) and (`order`.`status` = 10) ORDER BY `order`.`date_created` DESC LIMIT 1) as `last_order_delivery_date` 
        
        FROM `user` 
        
        LEFT JOIN `address` 
            ON user.address_id = address.id 
        LEFT JOIN `address_pickup` 
            ON user.pickup_address_id = address_pickup.id 
        LEFT JOIN `delivery_area` 
            ON user.delivery_area_id = delivery_area.id 
        LEFT JOIN `delivery_area_window` 
            ON delivery_area_window.id = delivery_area.delivery_area_window_id 
        LEFT JOIN `user_level` 
            ON user.level_id = user_level.id 
        LEFT JOIN `location` 
            ON address.location_id = location.id 
        LEFT JOIN `location_state` 
            ON location.state_id = location_state.id 
        LEFT JOIN `delivery_area` `delivery_area_by_location` ON delivery_area_by_location.location_id = location.id 
        LEFT JOIN (SELECT count(*) count, `user_id`, `code_id` FROM `order` WHERE (code_id > 0) and (`order`.`status` = 10) GROUP BY `user_id`, `code_id`) `code_used` 
            ON ((user.id = code_used.user_id) and (code_used.code_id = user.code_id)) 
        LEFT JOIN `code` 
            ON user.code_id = code.id WHERE (`user`.`type` = 0) and (`user`.`status` = 10) 
            
        GROUP BY `user`.`id` ORDER BY `last_name` LIMIT 15

UPD: CREATE TABLE

    CREATE TABLE `address` (
  `id` int(11) UNSIGNED NOT NULL,
  `location_id` int(11) UNSIGNED NOT NULL,
  `address` text NOT NULL,
  `unit` char(4) NOT NULL,
  `instructions` text NOT NULL,
  `regular` tinyint(1) NOT NULL DEFAULT '1',
  `topup` tinyint(1) NOT NULL DEFAULT '1',
  `date_from` date DEFAULT NULL,
  `date_to` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `address_pickup` (
  `id` tinyint(3) UNSIGNED NOT NULL,
  `address` text NOT NULL
) ENGINE=Aria DEFAULT CHARSET=utf8;

CREATE TABLE `code` (
  `id` smallint(6) UNSIGNED NOT NULL,
  `code` varchar(255) NOT NULL,
  `amount` decimal(7,2) NOT NULL,
  `value` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 - number; 1 - percent',
  `is_mswa` tinyint(4) DEFAULT '0',
  `is_permanent` tinyint(4) DEFAULT '0',
  `repeat` tinyint(4) DEFAULT '0',
  `apply_to` tinyint(4) DEFAULT '0' COMMENT '0 - both; 1 - box; 2 -  mp;',
  `times` int(11) NOT NULL DEFAULT '0',
  `date_created` datetime NOT NULL,
  `date_updated` datetime NOT NULL,
  `valid_from` date NOT NULL,
  `valid_until` date DEFAULT NULL,
  `author` varchar(255) NOT NULL,
  `checkout_text` text NOT NULL,
  `status` smallint(6) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `delivery_area` (
  `id` int(10) UNSIGNED NOT NULL,
  `location_id` int(11) NOT NULL,
  `fee` decimal(7,2) NOT NULL DEFAULT '0.00',
  `delivery_area_window_id` tinyint(4) UNSIGNED NOT NULL DEFAULT '1',
  `topup_available` tinyint(1) NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `delivery_area_window` (
  `id` tinyint(4) UNSIGNED NOT NULL,
  `day` tinyint(3) UNSIGNED NOT NULL,
  `day_name` varchar(255) NOT NULL,
  `day_name_full` varchar(255) NOT NULL,
  `window` varchar(255) NOT NULL DEFAULT '',
  `pickup` tinyint(4) NOT NULL DEFAULT '0'
) ENGINE=Aria DEFAULT CHARSET=utf8;


CREATE TABLE `gift` (
  `id` int(11) UNSIGNED NOT NULL,
  `user_id` int(11) UNSIGNED NOT NULL,
  `recipient_id` int(11) UNSIGNED NOT NULL,
  `type` tinyint(1) NOT NULL COMMENT '0 - card; 1 - box;',
  `message` text NOT NULL,
  `token` char(24) DEFAULT NULL,
  `order_id` int(11) UNSIGNED NOT NULL,
  `is_redeemed` tinyint(1) NOT NULL,
  `date_exp` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `location` (
  `id` int(10) UNSIGNED NOT NULL,
  `postcode` int(4) UNSIGNED NOT NULL,
  `suburb` varchar(45) NOT NULL,
  `dc` varchar(45) NOT NULL,
  `state_id` tinyint(3) UNSIGNED NOT NULL,
  `type_id` tinyint(4) UNSIGNED NOT NULL,
  `lat` double DEFAULT NULL,
  `lon` double DEFAULT NULL
) ENGINE=Aria DEFAULT CHARSET=utf8;

CREATE TABLE `location_state` (
  `id` tinyint(4) UNSIGNED NOT NULL,
  `code` char(3) NOT NULL,
  `state` varchar(255) NOT NULL
) ENGINE=Aria DEFAULT CHARSET=utf8;

CREATE TABLE `order` (
  `id` int(11) UNSIGNED NOT NULL,
  `user_id` int(11) UNSIGNED NOT NULL,
  `shipping_address_id` int(11) UNSIGNED NOT NULL,
  `topup_address_id` int(10) UNSIGNED NOT NULL,
  `pickup_address_id` tinyint(3) UNSIGNED DEFAULT NULL,
  `preferences` int(11) UNSIGNED NOT NULL,
  `referral_discount` decimal(7,2) NOT NULL DEFAULT '0.00',
  `code_id` int(11) UNSIGNED NOT NULL,
  `code_discount` decimal(7,2) NOT NULL DEFAULT '0.00',
  `pickup_discount` decimal(7,2) NOT NULL DEFAULT '0.00',
  `admin_discount` decimal(7,2) NOT NULL DEFAULT '0.00',
  `level_discount` decimal(7,2) NOT NULL DEFAULT '0.00',
  `delivery_fee` decimal(7,2) NOT NULL DEFAULT '0.00',
  `topup_delivery_fee` decimal(7,2) NOT NULL,
  `ondemand_fee` decimal(7,2) NOT NULL DEFAULT '0.00',
  `amount` decimal(7,2) NOT NULL DEFAULT '0.00',
  `retry_payment` tinyint(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '1-wait answer; 2-recharge with sms; 3-recharge without sms',
  `retry_payment_sms` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '0 - processed; >0 - sms id',
  `retry_payment_email` int(10) UNSIGNED NOT NULL DEFAULT '0',
  `eway_errors` text NOT NULL,
  `date_created` datetime NOT NULL,
  `date_updated` datetime NOT NULL,
  `delivery_date` date DEFAULT NULL,
  `status` smallint(6) UNSIGNED NOT NULL DEFAULT '10',
  `processing_status` smallint(6) UNSIGNED NOT NULL,
  `processing_status_edited` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `has_topup` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `is_topup_only` tinyint(1) UNSIGNED NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

CREATE TABLE `user` (
  `id` int(11) UNSIGNED NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `birthday` date DEFAULT NULL,
  `auth_key` varchar(32) NOT NULL,
  `password_hash` varchar(255) NOT NULL,
  `password_reset_token` varchar(255) DEFAULT NULL,
  `email` varchar(255) NOT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `custom_ref_code` varchar(255) DEFAULT NULL,
  `eway_id` bigint(20) UNSIGNED DEFAULT NULL COMMENT 'eWAY Customer Token ID',
  `active_campaign_id` int(11) UNSIGNED DEFAULT NULL COMMENT 'ActiveCampaign subscriber_id',
  `level_id` tinyint(4) UNSIGNED NOT NULL DEFAULT '1',
  `address_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
  `delivery_area_id` int(10) UNSIGNED DEFAULT NULL,
  `alt_address_id` int(10) UNSIGNED DEFAULT NULL,
  `alt_delivery_area_id` int(10) UNSIGNED DEFAULT NULL,
  `code_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
  `period` tinyint(4) UNSIGNED NOT NULL DEFAULT '1' COMMENT '1 - Once a Week; 2 - Fortnightly',
  `preferences` int(11) UNSIGNED NOT NULL DEFAULT '0',
  `is_pick_up` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `pickup_address_id` tinyint(3) UNSIGNED DEFAULT NULL,
  `is_active` tinyint(4) NOT NULL DEFAULT '1' COMMENT '0 - Inactive; 1 - Active; -1 - Blocked',
  `status` smallint(6) NOT NULL DEFAULT '10',
  `type` tinyint(4) UNSIGNED NOT NULL COMMENT '0 - Set And Forget; 1 - On Demand; 2 - Trial; 3 - Potential;',
  `first_delivery_date` date DEFAULT NULL,
  `last_delivery_date` date DEFAULT NULL,
  `change_delivery_date` date DEFAULT NULL,
  `nf_pantry_list` tinyint(1) NOT NULL DEFAULT '1',
  `nf_next_weeks_menu` tinyint(1) NOT NULL DEFAULT '1',
  `nf_paused_reminder` tinyint(1) NOT NULL DEFAULT '1',
  `nf_expected_delivery_time` tinyint(1) NOT NULL DEFAULT '1',
  `nf_delivery` tinyint(1) NOT NULL DEFAULT '1',
  `nf_welcome` tinyint(1) NOT NULL DEFAULT '1',
  `date_created` datetime NOT NULL,
  `date_updated` datetime NOT NULL,
  `consecutive_orders` smallint(5) UNSIGNED DEFAULT NULL,
  `orders_count` smallint(5) UNSIGNED NOT NULL DEFAULT '0',
  `rest_referral_discount` decimal(7,2) UNSIGNED NOT NULL,
  `rest_code_discount` decimal(7,2) UNSIGNED NOT NULL,
  `rest_code_box_discount` decimal(7,2) UNSIGNED NOT NULL,
  `rest_code_mp_discount` decimal(7,2) UNSIGNED NOT NULL,
  `rest_code_tup_discount` decimal(7,2) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `user_level` (
  `id` int(11) NOT NULL,
  `level` varchar(255) NOT NULL,
  `icon` varchar(255) NOT NULL,
  `description` text NOT NULL,
  `from` int(11) NOT NULL DEFAULT '0',
  `to` int(11) NOT NULL DEFAULT '0',
  `discount` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

And indexes

    --
-- Indexes table `address`
--
ALTER TABLE `address`
  ADD PRIMARY KEY (`id`),
  ADD KEY `location_id` (`location_id`),
  ADD KEY `regular` (`regular`),
  ADD KEY `topup` (`topup`),
  ADD KEY `date_to` (`date_to`),
  ADD KEY `date_from` (`date_from`);

--
-- Indexes table `address_pickup`
--
ALTER TABLE `address_pickup`
  ADD PRIMARY KEY (`id`);

--
-- Indexes table `code`
--
ALTER TABLE `code`
  ADD PRIMARY KEY (`id`),
  ADD KEY `status` (`status`),
  ADD KEY `valid_from` (`valid_from`),
  ADD KEY `valid_until` (`valid_until`),
  ADD KEY `date_created` (`date_created`),
  ADD KEY `code` (`code`) USING BTREE,
  ADD KEY `is_mswa` (`is_mswa`);

--
-- Indexes table `delivery_area`
--
ALTER TABLE `delivery_area`
  ADD PRIMARY KEY (`id`),
  ADD KEY `day` (`delivery_area_window_id`),
  ADD KEY `location_id` (`location_id`) USING BTREE,
  ADD KEY `friday_topup_available` (`topup_available`);

--
-- Indexes table `delivery_area_window`
--
ALTER TABLE `delivery_area_window`
  ADD PRIMARY KEY (`id`),
  ADD KEY `day` (`day`),
  ADD KEY `pickup_only` (`pickup`);

--
-- Indexes table `gift`
--
ALTER TABLE `gift`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `token` (`token`),
  ADD KEY `user_id` (`user_id`),
  ADD KEY `recipient_id` (`recipient_id`),
  ADD KEY `order_id` (`order_id`),
  ADD KEY `is_redeemed` (`is_redeemed`);

--
-- Indexes table `location`
--
ALTER TABLE `location`
  ADD PRIMARY KEY (`id`),
  ADD KEY `idx_lon` (`lon`),
  ADD KEY `idx_lat` (`lat`),
  ADD KEY `type_id` (`type_id`),
  ADD KEY `state_id` (`state_id`),
  ADD KEY `postcode` (`postcode`),
  ADD KEY `suburb_2` (`suburb`),
  ADD KEY `postcode_suburb` (`postcode`,`suburb`) USING BTREE;
ALTER TABLE `location` ADD FULLTEXT KEY `suburb` (`suburb`);

--
-- Indexes table `location_state`
--
ALTER TABLE `location_state`
  ADD PRIMARY KEY (`id`);

--
-- Indexes table `order`
--
ALTER TABLE `order`
  ADD PRIMARY KEY (`id`),
  ADD KEY `client_id` (`user_id`),
  ADD KEY `status` (`status`),
  ADD KEY `shipping_address_id` (`shipping_address_id`),
  ADD KEY `preferences` (`preferences`),
  ADD KEY `processing_status` (`processing_status`),
  ADD KEY `date_created` (`date_created`),
  ADD KEY `delivery_date` (`delivery_date`),
  ADD KEY `pickup_address_id` (`pickup_address_id`),
  ADD KEY `processing_status_edited` (`processing_status_edited`),
  ADD KEY `retry_payment_sms` (`retry_payment_sms`),
  ADD KEY `retry_payment` (`retry_payment`),
  ADD KEY `retry_payment_email` (`retry_payment_email`),
  ADD KEY `has_topup` (`has_topup`),
  ADD KEY `is_topup_only` (`is_topup_only`),
  ADD KEY `friday_address_id` (`topup_address_id`),
  ADD KEY `code_id` (`code_id`),
  ADD KEY `user_id` (`user_id`);

--
-- Indexes table `user`
--
ALTER TABLE `user`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `password_reset_token` (`password_reset_token`),
  ADD KEY `level_id` (`level_id`),
  ADD KEY `eway_id` (`eway_id`),
  ADD KEY `password_hash` (`password_hash`),
  ADD KEY `auth_key` (`auth_key`),
  ADD KEY `email` (`email`),
  ADD KEY `period` (`period`),
  ADD KEY `preferences` (`preferences`),
  ADD KEY `is_pick_up` (`is_pick_up`),
  ADD KEY `is_active` (`is_active`),
  ADD KEY `date_created` (`date_created`),
  ADD KEY `phone` (`phone`) USING BTREE,
  ADD KEY `active_campaign_id` (`active_campaign_id`),
  ADD KEY `custom_ref_code` (`custom_ref_code`),
  ADD KEY `consecutive_orders` (`consecutive_orders`),
  ADD KEY `pickup_address_id` (`pickup_address_id`),
  ADD KEY `rest_referral_discount` (`rest_referral_discount`),
  ADD KEY `rest_code_discount` (`rest_code_discount`),
  ADD KEY `rest_code_box_discount` (`rest_code_box_discount`),
  ADD KEY `rest_code_mp_discount` (`rest_code_mp_discount`),
  ADD KEY `delivery_area_id` (`delivery_area_id`),
  ADD KEY `rest_code_tup_discount` (`rest_code_tup_discount`),
  ADD KEY `orders_count` (`orders_count`),
  ADD KEY `alt_delivery_address_id` (`alt_address_id`),
  ADD KEY `alt_delivery_area_id` (`alt_delivery_area_id`),
  ADD KEY `address_id` (`address_id`),
  ADD KEY `code_id` (`code_id`),
  ADD KEY `status` (`status`),
  ADD KEY `type` (`type`),
  ADD KEY `last_name` (`last_name`);

--
-- Indexes table `user_level`
--
ALTER TABLE `user_level`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT
--
ALTER TABLE `address`
  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `address_pickup`
  MODIFY `id` tinyint(3) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `code`
  MODIFY `id` smallint(6) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `delivery_area`
  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `delivery_area_window`
  MODIFY `id` tinyint(4) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `gift`
  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `location`
  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `location_state`
  MODIFY `id` tinyint(4) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `order`
  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `user`
  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `user_level`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;

For table order :

INDEX(status, code_id, order_id)
INDEX(status, order_id, code_id)

(I can't tell which would be better; the Optimizer can decide.)

Don't use LEFT JOIN when the 'right' table is not optional. It makes it tedious for a human (and the Optimizer) to figure the intent.

User needs

 INDEX(type, status, code_id, code, id, last_name)

It is almost always beneficial to DROP INDEX(a) when you ADD INDEX(a,b). I bring that up because you probably have some one-column indexes.

If you need further help, please provide SHOW CREATE TABLE . I suspect that the query could be turned inside-out to great benefit. This involves finding the 15 ids first ; then after that do all the JOINs .

That might have this as the first "derived" table since it generates only 15 rows , not the 9976 estimated in the Explain:

FROM ( SELECT  id, `code`, code_id, last_name
        FROM user
        WHERE  `type` = 0
          AND  `status` = 10
        GROUP BY  `id`
        ORDER BY  `last_name`
        LIMIT  15
     ) AS u
JOIN ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM