explain 的 rows 值大但返回行少,说明mysql扫描大量索引/数据页却命中少,主因是查询未走索引、索引不覆盖select字段或函数/隐式转换导致失效;需检查type(避免all/index)、key(非null)、extra(避filesort/temporary);索引覆盖可省回表i/o,联合索引顺序须匹配where前置条件;函数操作、隐式转换等会使索引失效。

为什么 EXPLAIN 显示 rows 很大,但实际只返回几行?
这是索引没用对的典型信号——MySQL 扫描了大量索引/数据页,却只命中少量记录。根本原因常是:查询条件没走索引、索引无法覆盖 SELECT 字段、或用了函数/隐式转换导致索引失效。
- 检查
EXPLAIN的type字段:如果是ALL或index,说明在全表/全索引扫描;理想是ref、range或const - 确认
key列是否显示实际使用的索引名;若为NULL,代表没走索引 - 注意
Extra中出现Using filesort或Using temporary,往往意味着排序/分组被迫回表,放大扫描量
SELECT * 和 SELECT a,b,c 对索引扫描的影响差在哪?
差别在「索引覆盖」。如果所有要查的字段都在同一个索引里(包括 WHERE 条件字段 + SELECT 字段),MySQL 就不用回表查主键聚簇索引,直接从二级索引里拿完数据——这能砍掉 50% 以上的 I/O 开销。
- 例如表有索引
INDEX idx_status_created (status, created_at),执行SELECT status, created_at FROM t WHERE status = 'active'就是覆盖查询 - 但改成
SELECT *或加个name字段,就会触发回表,rows可能翻倍甚至更多 - 联合索引顺序很重要:WHERE 条件字段必须在前,SELECT 字段才能被覆盖;
created_at在status后面,那WHERE created_at > '2024-01-01'就无法用上这个索引
哪些写法会让明明建了索引也白搭?
不是建了索引就自动生效,很多日常写法会悄悄让优化器放弃索引。
- 对索引字段用函数:
WHERE YEAR(created_at) = 2024→ 改成WHERE created_at >= '2024-01-01' AND created_at - 隐式类型转换:
WHERE user_id = '123'(user_id 是 INT)→ 字符串强制转整型,可能丢索引;统一用123 - LIKE 左模糊:
WHERE name LIKE '%abc'无法走索引;右模糊'abc%'可以 - OR 连接不同字段:
WHERE a = 1 OR b = 2,除非 a、b 都有独立索引且满足特定条件,否则大概率全表扫
怎么验证一个查询到底有没有用上索引覆盖?
看 EXPLAIN 的 Extra 字段最直接:出现 Using index 表示走了覆盖索引;如果同时有 Using where,说明 WHERE 条件也在索引里完成过滤。
- 执行
EXPLAIN FORMAT=TRADITIONAL SELECT status, created_at FROM t WHERE status = 'active' - 若
Extra是Using where; Using index,恭喜,完全覆盖 - 若只有
Using where,说明用了索引找行,但还要回表取数据——这时候得检查 SELECT 字段是否超出了索引列范围 - 注意:覆盖索引对
COUNT(*)特别友好,只要索引非空,优化器常选最小二级索引加速统计











