MySQL慢查询和索引设计不当是性能瓶颈最常见的根源,优化需从执行路径出发,结合慢日志分析、EXPLAIN诊断及符合查询模式的索引设计。

MySQL慢查询和索引设计不当是性能瓶颈最常见的根源。真正有效的优化,不是盲目加索引或调参数,而是从查询执行路径出发,看清数据怎么被检索、连接、过滤和排序的。
看懂慢查询日志:定位真问题而不是猜
开启慢查询日志只是第一步,关键在如何读取和分析。默认记录的是“执行时间超阈值”的SQL,但很多慢查询其实源于逻辑错误(如没走索引的全表扫描)、隐式类型转换或不合理的JOIN顺序。
- 用mysqldumpslow快速聚合统计:比如
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log找出耗时TOP10的语句 - 对单条慢SQL,务必配合EXPLAIN分析:重点关注type(是否为
ALL或index)、key(实际使用的索引)、rows(预估扫描行数)、Extra(是否有Using filesort或Using temporary) - 注意EXPLAIN FORMAT=JSON能提供更细粒度信息,比如JOIN顺序、条件过滤率、是否使用ICP(Index Condition Pushdown)
索引设计原则:匹配查询模式,而非字段本身
索引不是越多越好,也不是给WHERE里的字段随便加一个就行。核心是让MySQL能用上索引完成“查找+过滤+排序”全过程。
-
最左前缀原则必须严格遵守:对联合索引
(a,b,c),只有WHERE a=1、WHERE a=1 AND b=2、WHERE a=1 AND b=2 AND c=3能高效使用;WHERE b=2或WHERE c=3基本无效 - 把高选择性字段放在联合索引左边:比如
status只有'active'/'inactive'两个值,就不适合放最左;而user_id或create_time通常更合适 - 覆盖索引能避免回表:如果
SELECT id, name, email FROM users WHERE status='active',建索引(status, id, name, email)可让查询完全走索引,不访问主键B+树
常见陷阱与实战修复示例
很多慢查询看似简单,实则藏着典型误区。以下是高频场景及对应解法:
-
LIKE '%xxx' 导致索引失效:改写为全文索引(
FULLTEXT)或倒排索引方案;若必须模糊前缀,考虑生成冗余字段(如email_reverse存反转邮箱,查WHERE email_reverse LIKE 'moc.elpmaxe%') -
隐式类型转换:比如
WHERE phone = 13812345678,而phone是VARCHAR类型,MySQL会把每行都转成数字比较,索引失效;应统一写成WHERE phone = '13812345678' -
ORDER BY + LIMIT 混合分页深翻:如
SELECT * FROM orders ORDER BY create_time DESC LIMIT 10000, 20,MySQL仍需扫描前10020行;改用游标分页:WHERE create_time
验证与持续监控:别让优化变成一次性动作
上线索引或改写SQL后,必须验证效果并建立长期观测机制,否则业务增长很快会让“已优化”再次变慢。
- 用pt-query-digest定期分析慢日志,生成趋势报告(比如某类查询平均响应时间周环比上升30%,就该介入)
- 在测试环境模拟真实流量:用sysbench或mysqlslap压测关键SQL,对比优化前后QPS、延迟、CPU/IO变化
- 在生产库启用Performance Schema或information_schema.PROFILING(5.7+推荐前者),追踪具体SQL各阶段耗时(Sending data、Sorting result等)











