直接看EXPLAIN输出是定位查询慢的原因最有效的起点,重点关注type(ALL为全表扫描)、key(为空说明未用索引)、rows(预估扫描行数远超结果集即异常)、Extra(出现Using filesort或Using temporary表明排序/分组未走索引)。

怎么看一条查询到底慢在哪
直接看 EXPLAIN 输出是最有效的起点。它不执行查询,只展示 MySQL 计划怎么走——用没用索引、是否全表扫描、是否临时表、是否文件排序,全在里面。
重点关注这几列:
-
type:值为ALL表示全表扫描,range或ref通常合理,const最理想 -
key:实际用到的索引名,为空说明没走索引 -
rows:预估扫描行数,远大于结果集行数(比如查 10 行却扫 10 万行)就是明显信号 -
Extra:出现Using filesort或Using temporary往往意味着排序或分组没走索引
为什么加了索引还是慢
索引不是万能的。常见失效场景比想象中多:
- 对索引字段做函数操作:
WHERE YEAR(create_time) = 2024→ 改成create_time BETWEEN '2024-01-01' AND '2024-12-31' - 隐式类型转换:
user_id是INT,但写成WHERE user_id = '123'→ 字符串触发全表扫描 - 最左前缀不匹配:
INDEX(a, b, c),但查询只用b = ?或c = ?→ 索引无法利用 - 数据分布倾斜严重:某值占 95% 行数,优化器可能直接放弃索引走全表
如何定位真实慢查询
别只靠开发反馈或肉眼观察。打开慢查询日志才是第一手依据:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 确认已启用:
SHOW VARIABLES LIKE 'slow_query_log';和slow_query_log_file - 设阈值(比如 1 秒):
SET GLOBAL long_query_time = 1.0;(注意会话级变量不生效) - 用
mysqldumpslow或pt-query-digest分析日志,聚焦Count高、Query_time avg高、Lock_time长的语句 - 特别留意
Rows_examined远大于Rows_sent的查询,说明大量无效扫描
ORDER BY 和 LIMIT 怎么避免拖垮性能
这两者组合是线上最常见的性能陷阱,尤其在分页深的时候:
-
SELECT * FROM orders ORDER BY created_at DESC LIMIT 100000, 20:MySQL 仍要先排好前 100020 行,再丢弃前 10 万 - 优化方向不是加索引,而是改写逻辑:用上一页最大/最小值做游标,例如
WHERE created_at - 如果必须跳页,确保
ORDER BY字段有索引,且和WHERE条件能共用同一索引(避免回表+排序双开销) - 注意
SELECT *在大表分页中代价极高,只查必要字段 + 覆盖索引更稳
真实瓶颈常藏在“看起来合理”的地方:比如一个被复用的通用查询模板,在数据量翻倍后突然变慢;或者一个 JOIN 表没加关联条件导致笛卡尔积。分析时别跳过 EXPLAIN 的 rows 和 Extra,它们比执行时间更早暴露问题。










