大表查询慢的核心是扫描行数过多,需结合查询条件、数据分布和执行计划精准优化;避免WHERE中函数、隐式转换或OR导致索引失效;务必用EXPLAIN分析执行计划并定期ANALYZE TABLE更新统计信息。

大表查询慢,核心问题常是扫描行数过多。减少扫描行数不是靠“加索引”一句话解决,而是要结合查询条件、数据分布、执行计划,精准缩小数据库实际读取的数据范围。
用好WHERE条件,让索引真正生效
即使有索引,如果WHERE中用了函数、类型隐式转换或OR连接多个非等值条件,索引可能失效,导致全表扫描。例如 WHERE YEAR(create_time) = 2023 会跳过索引;应改写为 WHERE create_time >= '2023-01-01' AND create_time 。
- 避免在索引列上使用函数、NOT、!=、LIKE '%xxx'(前导通配)
- IN列表不宜过长(一般不超过500项),否则优化器可能放弃索引走全表
- 复合索引要遵循最左匹配原则:(a,b,c) 索引支持 a、a+b、a+b+c 查询,但不支持 b 或 b+c 单独过滤
覆盖索引:只查索引,不回表
当SELECT字段和WHERE条件都能被同一个索引包含时,MySQL可直接从索引中获取全部所需数据,无需回主键索引查找行记录——这能显著减少IO和扫描行数。
- 例如查询 SELECT user_id, status FROM orders WHERE user_id = 123,若存在联合索引 (user_id, status),就构成覆盖索引
- 用 EXPLAIN 查看 Extra 列是否含 Using index
- 谨慎添加过多冗余字段到索引中,会增大索引体积、拖慢写入
限制结果集,用LIMIT配合ORDER BY注意陷阱
加LIMIT不等于减少扫描行数——如果ORDER BY字段无索引,MySQL仍需先排序全部匹配行,再取前N条。扫描行数可能远超LIMIT数值。
- 确保 ORDER BY 字段在索引中,并与WHERE条件列组合成有效复合索引
- 避免 ORDER BY RAND(),它必然触发全表扫描+临时表排序
- 分页深翻(如 LIMIT 1000000, 20)效率低,建议用游标分页(记录上一页最大ID,下一页查 > ID)
统计信息准确 + 执行计划驱动优化
优化不能靠猜。每次调优前,先用 EXPLAIN 看实际执行计划,重点关注 rows(预估扫描行数)、key(实际使用的索引)、Extra(是否有Using filesort/Using temporary)。
- 定期执行 ANALYZE TABLE table_name 更新统计信息,帮助优化器选对执行路径
- 对数据倾斜严重的列(如 status=0 占99%),索引效果差,可考虑分区、冗余字段或业务层拆分查询逻辑
- 必要时用 FORCE INDEX 强制走某索引(慎用,需验证稳定性)










