问题描述
我有一个包含 12 1
的繁重 MysqL 查询,并注意到一些表具有 category3
引擎和一些 LEFT JOIN
。
我已附上此查询的 InnoDB
,并用相应的字母 Aria
和 EXPLAIN
将引擎类型指向图像。
不同引擎的事实对查询速度有影响吗?严重程度如何?更改引擎类型是否有助于优化查询执行?
我还能做些什么来优化这个查询?
查询(如果需要)
I
更新:A
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,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,code_used.count,0) code_used_count,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
和索引
CREATE TABLE
解决方法
对于表 order
:
INDEX(status,code_id,order_id)
INDEX(status,order_id,code_id)
(我不知道哪个更好;优化器可以决定。)
当“右”表不是可选的时,不要使用 LEFT JOIN
。人类(和优化器)弄清意图变得乏味。
User
需要
INDEX(type,status,code,id,last_name)
当您添加 INDEX(a,b) 时,DROP INDEX(a) 几乎总是有益的。我提出这一点是因为您可能有一些单列索引。
如果您需要进一步的帮助,请提供SHOW CREATE TABLE
。我怀疑该查询可以由内而外转换以获得很大的好处。这涉及到 first 找到 15 个 id;然后在那之后做所有的JOINs
。
这可能是第一个“派生”表,因为它只生成 15 行,而不是解释中估计的 9976:
FROM ( SELECT id,`code`,last_name
FROM user
WHERE `type` = 0
AND `status` = 10
GROUP BY `id`
ORDER BY `last_name`
LIMIT 15
) AS u
JOIN ...