生产环境MySQL全表扫描慢事务定位方法

作者:技术拾光时间:2026-07-14 08:28:06浏览:401

通过EXPLAIN的type字段为ALL、key为NULL、rows接近总行数等信号可判断全表扫描。使用SHOWPROCESSLIST或INFORMATION_SCHEMA.PROCESSLIST快速定位慢查询。索引失效常见于函数调用、隐式类型转换、左模糊查询及联合索引顺序错误。建议优先覆盖WHERE条件加索引,并用pt-online-schema-chan

判断一条SQL是否在走全表扫描,最直接的办法就是看`EXPLAIN`输出里的`type`字段。只要它显示为`ALL`,那就是铁定没走索引——不是“可能”,是实锤。除此之外,还有几个关键信号值得一并盯住:`key`字段为`NULL`、`rows`数量接近总行数、`Extra`里出现`Using where`但没有`Using index`。这些信号组合在一起,基本可以断定MySQL正在硬着头皮扫全表。 生产环境MySQL全表扫描慢事务定位方法 ## 怎么快速揪出正在全表扫描的 SQL? 别等到慢查询日志积累半天才去翻。先连上生产库,直接用`SHOW PROCESSLIST`看当前活跃会话里哪些在扫大表: - `State`是`Sending data`且`Time`超过几秒,大概率在扫; - `Info`字段里带`SELECT` + 大量`WHERE`条件但没`ORDER BY`或`LIMIT`,尤其要留意有没有函数调用(比如`DATE(created_at)`这种); - 配合`INFORMATION_SCHEMA.PROCESSLIST`查得更全:`SELECT ID, INFO, TIME FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Query' AND TIME > 3 AND INFO LIKE '%SELECT%';` ## EXPLAIN 里哪些信号说明它在全表扫描? `EXPLAIN`不是看热闹,重点盯三个字段: - `type`是`ALL`:铁证,没走任何索引; - `key`是`NULL`:即使`possible_keys`有值,`key`为空也等于没用; - `rows`数字极大(比如超过50000):哪怕`type`是`index`,扫整张索引树也等价于全表扫描; - `Extra`出现`Using where`但没`Using index`:说明查了索引还得回表,如果`rows`很大,实际开销接近全表。 ## 为什么明明建了索引还全表扫描?常见失效场景 索引存在 ≠ 被用。这几个写法会让MySQL直接放弃索引: - WHERE中对字段用了函数:`WHERE YEAR(create_time) = 2026` → 改成`WHERE create_time >= '2026-01-01' AND create_time < '2027-01-01'`; - 隐式类型转换:`WHERE user_id = '123'`(`user_id`是INT)→ 字符串强制转数字,索引失效; - LIKE左模糊:`WHERE name LIKE '%abc'` → 没法走B+树前缀匹配; - 联合索引顺序错:`INDEX(a,b,c)`,但查询只用`WHERE c = 1` → 不满足最左前缀,直接跳过。 ## 线上不敢随便改 SQL?先加索引试试 如果确认是缺失索引导致的`ALL`,加索引比重写业务逻辑快得多,但要注意: - 优先覆盖`WHERE`条件字段,再追加`ORDER BY`和`SELECT`字段(做成覆盖索引); - 避免单列索引堆砌,比如`WHERE a=1 AND b=2`,建`INDEX(a,b)`比分别建两个好; - 加索引前用`pt-online-schema-change`或MySQL 8.0+的`ALGORITHM=INSTANT`,别锁表; - 加完立刻`EXPLAIN`验证,别信“应该能走”。 全表扫描本身不致命,致命的是它出现在高频接口或大表上。真正麻烦的是那些`rows`显示几千、但实际执行扫了百万行的SQL——`EXPLAIN`的预估不准时,得靠`SHOW PROFILE`或性能模式(`performance_schema`)看真实I/O开销。