强制走索引sql

 人参与 | 时间:2026-10-17 06:51:58

MySQL里有个老生常谈的强制调优手段:强制走索引。但很多人用错了地方,走索把FORCE INDEX当成万能膏药,强制哪疼贴哪。走索我见过最离谱的强制一次,开发在一条查询里硬塞了三个FORCE INDEX,走索结果慢查询日志直接爆红——优化器本来选得好好的强制索引,被强制切换后反而要回表三千次。走索

先说结论:FORCE INDEX只适合两种情况。强制第一种,走索你比优化器更懂数据分布。强制比如索引列上有大量重复值,走索统计信息又没及时更新,强制优化器误判了基数,走索选了全表扫描。强制第二种,生产环境出了紧急事故,没时间调参,先强制走索引止血。

上个月排查过一个真实案例。订单表三千万行,查询条件是status=1 AND create_time>='2024-01-01'。表上有联合索引(status, create_time),但优化器偏偏选了另一个只有create_time的二级索引。为啥?因为status=1的数据占比超过40%,优化器觉得回表成本太高,不如走时间索引再过滤。可实际业务里status=1的订单大多在最近三个月,联合索引的过滤效果更好。这时候FORCE INDEX(idx_status_time)一条指令下去,查询时间从1.8秒降到0.2秒。

但别高兴太早。强制索引有个致命陷阱——它会冻结执行计划。数据量涨了,索引基数变了,或者查询条件里的常量值变了,你写死的那个索引可能就成了累赘。我见过一个报表系统,上线时跑得飞快,半年后数据翻倍,SQL还是强制走老索引,结果每次查询要扫五倍的数据页。最后DBA半夜爬起来删掉FORCE INDEX,让优化器自己选,反而快了三倍。

所以我的习惯是:FORCE INDEX只用来应急,绝不写进业务代码的长期版本里。真要根治,得去查为什么优化器选错索引。常见原因有三个:统计信息过期(跑一次ANALYZE TABLE)、索引选择性太差(考虑重建复合索引)、或者查询写法导致隐式类型转换(比如字符串列没加引号)。

还有个细节容易被忽略:FORCE INDEX在MySQL 8.0里的行为其实变了。8.0的优化器更智能,支持SKIP SCAN和INDEX MERGE,很多时候你强行指定索引,反而抑制了这些新特性。我试过一条查询,用FORCE INDEX走了A索引要扫十万行,不强制时优化器自动合并两个索引,只扫一万行。版本升级后,旧SQL里写死的FORCE INDEX成了性能杀手。

最后说个实操建议。真要强制索引,别用FORCE INDEX,用USE INDEX。区别在于FORCE是“必须用”,USE是“优先用”——后者给了优化器反悔的余地。万一你判断错了,优化器还能自己纠偏。我自己的项目里,凡是见过FORCE INDEX的代码review,一律打回重写,要求附带执行计划说明为什么非它不可。

索引是门权衡的艺术,强制走索引等于你替优化器做了决定。可以偶尔这么做,但别养成习惯。毕竟数据库比你更懂数据,除非它病了,否则别抢它的方向盘。

顶: 1421踩: 82178