需同时开启slow_query_log、设置log_queries_not_using_indexes=on并调低long_query_time,再结合rows_examined值与explain的type=all确认全表扫描。

如何确认慢日志已开启且记录了全表扫描
MySQL 5.7 默认不启用慢查询日志,更不会自动记录未使用索引的查询。必须手动配置 slow_query_log、long_query_time,并关键地设置 log_queries_not_using_indexes = ON —— 否则即使执行了全表扫描,只要耗时没超 long_query_time,就不会进慢日志。
检查当前配置:
SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time'; SHOW VARIABLES LIKE 'log_queries_not_using_indexes';
若未开启,需在 my.cnf 中补充(重启生效):
slow_query_log = ON slow_query_log_file = /var/lib/mysql/slow.log long_query_time = 1 log_queries_not_using_indexes = ON
-
long_query_time设为 1 秒是常见起点,但全表扫描可能远低于此值(比如小表查 10ms),所以log_queries_not_using_indexes是抓全表扫描的核心开关 - 线上环境慎用
log_queries_not_using_indexes = ON,它会显著增加日志量,建议仅用于短时排查 - 日志路径需确保 MySQL 进程有写权限,否则日志静默失败
从慢日志里快速定位全表扫描语句
MySQL 5.7 的慢日志默认不直接标注“全表扫描”,但会通过 Rows_examined 和执行计划线索暴露问题。重点看三处:
- 每条日志开头的
# Query_time行后紧跟着的Rows_examined值:若该值接近表总行数(如Rows_examined: 124892而表只有 13 万行),基本就是全表扫 - 日志中是否含
Using where; Using index condition等提示 —— 缺失这类信息,尤其只有Using where,往往意味着没走有效索引 - 语句本身是否含
WHERE条件但字段无索引,或用了函数/隐式类型转换(如WHERE DATE(create_time) = '2024-01-01')
用 mysqldumpslow 快速聚合高 Rows_examined 的语句:
mysqldumpslow -s r -t 10 /var/lib/mysql/slow.log
-s r 按 Rows_examined 排序,比按时间排序更能揪出“快但伤库”的全表扫描。
验证某条语句是否真走了全表扫描
日志只是线索,最终得用 EXPLAIN 看执行计划。对慢日志里抓到的可疑语句,连上数据库执行:
EXPLAIN SELECT * FROM orders WHERE status = 'pending';
重点关注几列:
-
type:值为ALL就是全表扫描;index是遍历索引树(仍算扫描,但通常更快);range/ref才是合理索引访问 -
key:为NULL表示没用上索引(注意:可能建了索引但因条件不匹配未被选中) -
rows:预估扫描行数,和日志里的Rows_examined对得上,说明预估靠谱 -
Extra:出现Using filesort或Using temporary不直接等于全表扫,但常伴随低效查询逻辑
注意:5.7 的 EXPLAIN FORMAT=JSON 能看到更细的 filtered(条件过滤率),若 filtered 极低(如 0.1%),说明虽然走了索引,但实际仍要读大量索引/数据页,效果接近全表扫。
修复时最容易忽略的索引陷阱
加索引不是万能解药,5.7 下几个典型坑:
- 复合索引顺序错:如
WHERE a = ? AND b > ?,索引应建为(a, b),而非(b, a)—— 后者b > ?无法用上范围查找 - 字符串字段没指定长度:
VARCHAR(255)列上建索引却只写INDEX(col),InnoDB 可能因长度超限制而拒绝使用索引,需显式INDEX(col(191)) - 统计信息过期:
SELECT COUNT(*)结果突变后,优化器可能误判索引效率,运行ANALYZE TABLE table_name;更新统计 - 隐式转换:
user_id是INT,但 SQL 里写了WHERE user_id = '123',触发字符串转数字,索引失效
修复后务必用原语句再跑一次 EXPLAIN,确认 type 变成 ref 或 range,且 rows 显著下降。别只看“用了索引”,要看它是不是真的高效用了。











