FORCE INDEX 是强制MySQL优化器使用指定B-tree索引的语法,必须写在FROM后、括号内填真实索引名,仅对单表生效,错误则报错,需结合EXPLAIN验证实际效果。

FORCE INDEX 用在 WHERE 条件不走索引时
MySQL 优化器有时会“误判”索引价值,比如表数据量小、统计信息过期、或 WHERE 中用了函数导致索引失效,结果走了全表扫描。这时 FORCE INDEX 是明确告诉优化器:“就用这个索引,别犹豫”。它不是万能药,但比 USE INDEX 更强硬——后者只是建议,前者会直接拒绝执行计划中不含该索引的路径。
常见错误现象:EXPLAIN 显示 type=ALL 或 key=NULL,但明明有合适索引;加了 WHERE col = ? 却没走 col 上的索引。
- 只对单表生效,JOIN 场景下需对每个表分别指定
- 语法必须紧跟在
FROM table_name后,不能放在WHERE后面 - 索引名写错或不存在,查询会直接报错:
ERROR 1176 (HY000): Key 'xxx' doesn't exist in table 'yyy' - 如果强制的索引根本覆盖不了查询字段(比如没包含 SELECT 中的列),可能触发回表+排序,性能反而更差
FORCE INDEX 的正确写法和典型位置
核心是位置和括号:必须写成 FROM t FORCE INDEX (idx_name),括号不能省,索引名是真实存在的 B-tree 索引名(不是列名)。
使用场景:排查慢查时临时验证某个索引是否真能提升性能;线上紧急绕过优化器 bug;测试不同索引对 ORDER BY + LIMIT 的影响。
SELECT * FROM orders FORCE INDEX (idx_status_created) WHERE status = 'paid' ORDER BY created_at DESC LIMIT 10;- 多列索引要写全名:
FORCE INDEX (idx_user_id_type_time),不能简写成idx_user_id - 主键也是索引,可强制:
FORCE INDEX (PRIMARY),注意大写 PRIMARY - 复合索引中,只要 WHERE 条件匹配最左前缀,强制才有意义;否则即使指定了,MySQL 也用不上
FORCE INDEX 和 IGNORE INDEX 容易混淆的点
IGNORE INDEX 是反向操作,用来排除某个索引,常用于调试“为什么优化器选了烂索引”。但它不保证一定走别的索引——如果只剩全表扫描可选,还是会扫。
两者不能共存;也不能和 USE INDEX 混用。一旦用了 FORCE INDEX,优化器就失去对那个表的索引选择权。
- 错误写法:
FROM t USE INDEX (a) FORCE INDEX (b)→ 语法错误 - 错误写法:
FROM t FORCE INDEX (idx_a, idx_b)→ 不支持多个索引逗号分隔,只认一个 - 如果表有前缀索引(如
INDEX (name(10))),强制时必须用完整索引名,不能只写name -
FORCE INDEX对全文索引(FULLTEXT)无效,仅适用于 B-tree 类型索引
强制索引后还要看执行计划是否真生效
加了 FORCE INDEX 不等于性能就变好。必须用 EXPLAIN FORMAT=TREE 或至少 EXPLAIN 确认 key 列确实显示你指定的索引名,且 rows 显著减少。
容易被忽略的地方:索引虽然强制用了,但 Extra 里出现 Using filesort 或 Using temporary,说明排序/分组仍没走索引,瓶颈可能转移了。
- 检查
ORDER BY字段是否包含在强制的索引中,且顺序一致 - 确认
WHERE条件中的列是索引最左前缀,否则即使强制,实际也只用到部分长度 - 如果表有大量 DELETE/UPDATE,统计信息可能不准,先跑
ANALYZE TABLE t;再测 - 上线前务必在从库或影子库验证,避免主库因强制索引引发锁竞争或内存暴涨










