EXPLAIN 的 rows 值远大于实际结果数,说明 MySQL 预估扫描行数多但靠 WHERE 过滤后仅剩几条;主因是缺失合适索引或 WHERE 中使用函数/运算导致索引失效,应按谓词组合建立符合最左前缀的联合索引。

EXPLAIN 显示 rows 值特别大,但实际结果只有几条
这说明 MySQL 在执行前预估要扫描大量行,但最终靠 WHERE 条件过滤掉绝大部分——问题不在结果少,而在“先扫再筛”太粗暴。常见于缺少合适索引、或条件用了无法走索引的写法。
- 检查
WHERE中字段是否有单列索引或符合最左前缀的联合索引;没有就加,别只看SELECT字段 - 避免在索引字段上用函数或运算,比如
WHERE YEAR(create_time) = 2024会让create_time索引失效,改成WHERE create_time >= '2024-01-01' AND create_time - 字符串比较注意隐式类型转换:
WHERE user_id = '123'(user_id是INT)会触发全表扫描,统一类型写成WHERE user_id = 123
LIKE '%关键词' 导致 rows 暴涨
以通配符开头的模糊查询无法使用 B+ 树索引的有序性,MySQL 只能全索引扫描甚至全表扫描。
- 能改写就改写:比如搜索日志中的错误码,优先用
WHERE error_code = 'ERR_500'而不是WHERE log_content LIKE '%ERR_500%' - 真要模糊查内容,且数据量大,考虑把高频检索字段单独提取出来建索引,或引入
FULLTEXT索引(仅 MyISAM/InnoDB 支持,但对中文需分词支持) -
LIKE '前缀%'是安全的,可以走索引;但LIKE '%前缀%'或LIKE '%前缀'都不行
OR 连接多个条件让索引失效
MySQL 对 OR 的索引优化较弱,尤其当两边字段无共同索引时,容易放弃所有索引,退化为全表扫描。
- 优先拆成
UNION:比如WHERE a = 1 OR b = 2改成(SELECT ... WHERE a = 1) UNION ALL (SELECT ... WHERE b = 2),前提是两个子查询都能走各自索引 - 确保
OR两侧字段都包含在同一联合索引中,且满足最左前缀,例如索引是(a, b),那么WHERE a = 1 OR b = 2仍可能只用上a部分,b = 2那部分还是扫 - 用
IN替代多个等值OR:如WHERE status = 'A' OR status = 'B' OR status = 'C'直接写成WHERE status IN ('A','B','C'),这个能走索引
ORDER BY + LIMIT 配合不当,放大扫描量
看似只取 10 条,但 MySQL 可能先按 ORDER BY 排序全部匹配行,再截取——尤其当 WHERE 过滤后仍有大量数据时。
- 确保
ORDER BY字段和WHERE条件字段一起建联合索引,顺序按“过滤字段在前、排序字段在后”,例如WHERE category = ? ORDER BY created_at DESC,建索引(category, created_at) - 如果
WHERE条件本身选择率低(比如WHERE is_deleted = 0),而is_deleted基本都是 0,那这个条件几乎不减少扫描行数,得换更有效的过滤维度 -
LIMIT不会减少EXPLAIN中的rows值,它只影响实际执行阶段的数据传输量;所以rows大 ≠ 返回慢,但大概率意味着执行计划不够优
真正卡住的往往不是单个技巧,而是多个条件叠加后索引覆盖不全——比如 WHERE a = ? AND b > ? ORDER BY c,需要的是 (a, b, c) 联合索引,漏掉任意一环,rows 就可能翻几倍。调的时候别只盯着一个字段加索引,得看整个谓词组合。


















