默认 slow_log 查不到全表扫描sql,因其仅记录超 long_query_time 的语句;小表全表扫描可能远低于阈值。需开启 log_queries_not_using_indexes=on(配合 long_query_time=0)才能捕获所有未走索引的查询,包括毫秒级全表扫描。

为什么 slow_log 里查不到全表扫描的 SQL?
默认情况下,MySQL 的 slow_query_log 只记录执行时间超过 long_query_time 的语句,而一个轻量级的全表扫描(比如小表、缓存命中高、数据页在 buffer pool)可能 0.1 秒就跑完,根本进不了慢日志——但这类语句并发一高,Handler_read_* 指标和磁盘 IO 就会飙升。
真正该开的是 log_queries_not_using_indexes = ON,它会把所有没走索引的查询(包括全表扫描、索引扫描但未命中 WHERE 条件的)都记进慢日志,哪怕执行时间只有几毫秒。
- 必须搭配
long_query_time = 0(否则log_queries_not_using_indexes在某些旧版本中不生效) - 注意:开启后日志量激增,建议先在低峰期测试,用
mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log快速看 Top 耗时语句 - 5.7+ 版本还支持
log_throttle_queries_not_using_indexes,可限制每分钟最多记录多少条无索引查询,避免日志撑爆磁盘
如何确认某条 SQL 真的是全表扫描?
光看慢日志里的 SQL 不够,得看执行计划。重点不是 EXPLAIN 输出里有没有 type=ALL,而是结合 rows 和 filtered 判断实际扫描行数是否远超返回行数。
-
rows是 MySQL 预估的扫描行数;如果比SELECT COUNT(*) FROM table还大,说明预估严重失真,往往意味着统计信息过期,ANALYZE TABLE table_name能临时缓解 -
filtered值极低(比如 0.1),表示 WHERE 条件过滤效率差,即使有索引也可能退化成索引扫描+回表,IO 压力不比全表扫描小 - 特别注意
Extra字段:出现Using where; Using filesort或Using temporary时,即使type是ref,也可能因排序/临时表触发大量磁盘读写
哪些常见写法会悄悄触发全表扫描?
很多看似“合理”的 SQL,在特定条件下直接放弃索引,开发者很难第一时间察觉。
- 对索引字段做函数操作:
WHERE YEAR(create_time) = 2024→ 改成WHERE create_time BETWEEN '2024-01-01' AND '2024-12-31' - 隐式类型转换:
WHERE user_id = '123'(user_id是 INT)→ 字符串转数字导致索引失效,错误日志里会看到Cannot use range access on index 'idx_user_id' due to type or collation conversion - LIKE 左模糊:
WHERE name LIKE '%abc'→ 没法用 B+ 树索引,只能扫全表;右模糊LIKE 'abc%'是可以走索引的 - OR 条件混用不同索引:
WHERE a = 1 OR b = 2(a、b 各有单列索引)→ MySQL 5.6+ 默认不合并索引,容易走全表;改用UNION或联合索引更稳
IO 打满时怎么快速定位并止损?
等系统已经卡死再查慢日志,往往来不及。要提前建立观测链路,并准备好应急手段。
- 实时盯
SHOW GLOBAL STATUS LIKE 'Handler_read%':如果Handler_read_rnd_next(随机读行)或Handler_read_full_table(全表扫描次数)突增,比 CPU 或连接数更能反映 IO 压力源头 - 用
pt-query-digest分析慢日志时加--filter '$event->{Rows_examined} > 10000',跳过那些“快但扫得多”的干扰项 - 紧急情况下可临时禁用问题 SQL:用
SET GLOBAL max_execution_time = 1000给所有语句加 1 秒超时,或通过mysqladmin kill干掉已运行的长耗时连接 - 别忘了检查
innodb_buffer_pool_size是否过小——缓冲池太小会导致本该内存完成的读被压到磁盘,放大全表扫描的破坏力
全表扫描本身不是 bug,但高频、大表、无节制地扫,就是 IO 灾难的导火索。关键是把“没走索引”这件事从黑盒变成可观测项,而不是等磁盘队列长度飙到 100 才去翻日志。











