凌晨三点的告警:EXPLAIN对比优化拯救了一条慢查询凌晨三点,监控系统突然弹出告警,核心订单查询接口响应时间飙到了12秒。用户投诉像雪片一样飞来,运维兄弟的电话被打爆。排查了半天,最后定位到一条再普通不过的关联查询——就是那种每个开发都写过、却从没认真优化过的SQL。这条查询在测试环境跑得飞快,到了生产环境数据量一上来,直接把数据库拖成了半死不活。今天这篇文章,我就拿这条SQL的调优过程当靶子,从EXPLAIN执行计划的对比分析入手,一步步拆解索引策略和查询优化的实战技巧,希望能帮你少踩几个坑。数据库索引策略与EXPLAIN执行计划对比分析实战一、问题还原:一条"看似简单"的慢查询事情要从一个典型的电商订单查询说起。业务方需要拉取某个时间段内,某个店铺下所有已完成订单的商品明细,同时要关联商品表和店铺表,统计每个商品的销售数量和总金额。原始SQL如下:sqlSELECTo.order_id,o.order_no,p.shop_name,g.goods_name,SUM(gi.quantity) AS total_qty,SUM(gi.quantity * gi.unit_price) AS total_amountFROMt_order oLEFT JOIN t_order_goods gi ON o.order_id = gi.order_idLEFT JOIN t_goods g ON gi.goods_id = g.goods_idLEFT JOIN t_shop p ON o.shop_id = p.shop_idWHEREo.shop_id = 1023AND o.status = 3AND o.create_time BETWEEN '2024-01-01' AND '2024-12-31'GROUP BYo.order_id, o.order_no, p.shop_name, g.goods_nameORDER BYtotal_amount DESC;这条SQL在测试环境只有几千条数据时,执行时间大概200毫秒,看起来完全没问题。但生产环境里,t_order表有1800万条记录,t_order_goods表有4500万条记录,执行时间直接干到了11.8秒。二、EXPLAIN执行计划对比:从数字里读出真相2.1、优化前的EXPLAIN分析先看优化前的执行计划关键信息:id select_type table type possible_keys key key_len rows Extra1 SIMPLE o ALL idx_shop_status_time NULL NULL 18234567 Using where; Using temporary; Using filesort1 SIMPLE gi ref idx_order_id idx_order_id 8 3 NULL1 SIMPLE g eq_ref PRIMARY PRIMARY 8 1 NULL1 SIMPLE p eq_ref PRIMARY PRIMARY 4 1 NULL这张表一看就能发现几个致命问题:1、主表t_order的type是ALL,意味着全表扫描。possible_keys里虽然有idx_shop_status_time这个联合索引,但实际并没有被用上,rows显示扫描了1823万行,这就是慢的根源。2、Extra字段出现了Using temporary和Using filesort,说明分组和排序都没用上索引,MySQL不得不在内存里建临时表、做文件排序,数据量一大直接爆内存。