简体   繁体   English

MySQL 不同的引擎类型(InnoDB 和 Aria)是否会影响具有大量 LEFT JOIN 的查询?

[英]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 .我有一个带有 12 LEFT JOIN的重型 MySQL 查询,并注意到一些表有InnoDB引擎和一些Aria I've attached EXPLAIN of this query and pointed engine types at image with corresponding letters I and A .我已经EXPLAIN了这个查询的解释,并在图像上用相应的字母IA指出了引擎类型。

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 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 :对于表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.当“右”表不是可选的时,不要使用LEFT JOIN It makes it tedious for a human (and the Optimizer) to figure the intent.这使得人类(和优化器)确定意图变得乏味。

User needs User需求

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

It is almost always beneficial to DROP INDEX(a) when you ADD INDEX(a,b).当您添加 INDEX(a,b) 时,DROP INDEX(a) 几乎总是有益的。 I bring that up because you probably have some one-column indexes.我提出这个是因为你可能有一些单列索引。

If you need further help, please provide SHOW CREATE TABLE .如果您需要进一步的帮助,请提供SHOW CREATE TABLE I suspect that the query could be turned inside-out to great benefit.我怀疑这个查询可以从里到外翻到很大的好处。 This involves finding the 15 ids first ;这涉及首先找到 15 个 id; then after that do all the JOINs .然后在那之后做所有的JOINs

That might have this as the first "derived" table since it generates only 15 rows , not the 9976 estimated in the Explain:这可能是第一个“派生”表,因为它只生成15 行,而不是解释中估计的 9976:

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 ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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