MySQL 慢查询:先读执行计划再添加索引

页面列表越来越慢时,给每个字段添加索引并不能保证改善。问题可能是扫描范围、排序、连接顺序或返回数据量,应先保留原 SQL 和实际查询条件。

edyang · 2020-02-23

页面列表越来越慢时,给每个字段添加索引并不能保证改善。问题可能是扫描范围、排序、连接顺序或返回数据量,应先保留原 SQL 和实际查询条件。

索引用于缩小定位和排序成本,但维护索引会增加写入开销。联合索引的列顺序影响可利用前缀,条件选择性和数据分布影响优化器判断。EXPLAIN 展示计划线索,不自动给出真实执行耗时。

MySQL 慢查询:先读执行计划再添加索引:处理路径与验证条件

一、问题的范围与前提

数据库连接、事务、SQL 执行和数据结果应分别验证。一次连接成功不证明事务可写,也不证明原有查询在不同数据库上结果相同。应从实际业务入口取得证据,记录角色、数据库、事务范围与查询条件,再分析执行计划或连接池。

二、技术分析与方案取舍

例如设备事件列表按 device_id 过滤,再按 created_at 和 id 排序,可以研究与查询相匹配的联合索引。但索引列越多不必然越好:字段选择性、返回列和写入频率都会影响代价。EXPLAIN 中 rows 是估计,不应当成实际扫描计数;不同参数还可能选择不同计划。

对照测试应使用真实数量级与分布,并检查查询结果是否完全一致,而不只观察响应更快。

测试数据先覆盖正常输入、边界值和并发条件。精度、空值、时间和关联约束需要固定规则,更新语句应处于明确事务中。对于会产生写入的试验,使用独立测试环境并准备恢复方法;只读执行计划也应核对查询是否会调用带副作用的函数。

三、实现与排查的顺序

  1. 固定具有代表性的查询参数。
  2. 查看扫描方式和估计行数。
  3. 把过滤与排序一起分析。
  4. 在副本或测试环境比较索引方案。

按这个顺序保留中间结果,可以区分输入条件、处理过程和最终输出。前一阶段的条件不成立时,先解释对应错误,再继续后面的试验;单次返回成功不足以覆盖整条链路。

最小示例

1
2
3
4
5
EXPLAIN SELECT id, created_at
FROM example_event
WHERE device_id = 1
ORDER BY created_at DESC, id DESC
LIMIT 20;

表名与条件是示意,目标库需有对应结构。计划中的估计行数和扫描类型提供线索,实际耗时仍需按目标数据库方法测量。排序补充唯一键有助于稳定结果,索引方案要同时考虑过滤、排序和写入成本。

四、验证和结果解释

查询结果可以按主键集合、字段值和关联关系核验,不宜仅比较总行数。性能记录应同时保留参数、数据规模、缓存状态与并发条件。错误时检查服务端实际连接和活动事务,避免只观察另一台实例或另一份会话。

需要验证的结果 保留的对照 不能由此推出的结论
查询返回集合保持一致 固定输入与配置、对应输出 一次成功代表所有条件成功
常见与边界参数都有改善 中断前后状态与错误阶段 没有报错代表结果正确
写入和存储成本仍满足约束 恢复后的同条件复测 临时恢复代表根因已经消失

重试、刷新连接和改变数据库角色属于不同操作。异常后先确定处理结果,再决定重复执行;跨外部接口的业务还需要幂等和补偿。备份恢复与数据迁移必须演练,回到旧程序版本不自动恢复被修改的持久数据。

五、适用边界与结论

小测试表上的全表扫描可能是合理选择。函数包裹、隐式类型转换和前导通配符会影响索引使用,但具体结果应由目标版本计划确认。

这条路径把“固定具有代表性的查询参数”与“在副本或测试环境比较索引方案”连在一起,中间保留可复查的条件。实施时优先确认“查询返回集合保持一致”,再检查“写入和存储成本仍满足约束”;两者都满足,才能在当前样本与配置范围内评价方案。设备、数据或软件版本改变以后,相关假设需要重新验证。

参考资料