<p>FORCE INDEX语法为SELECT * FROM table_name FORCE INDEX (index_name) WHERE ...,必须紧接表名后、WHERE前;index_name须真实存在且大小写敏感,多索引用逗号分隔但仅选其一;不可用于表达式或列名,特殊字符需加反引号。</p>

FORCE INDEX 语法怎么写,有哪些必须注意的参数
MySQL 的 FORCE INDEX 不是函数,而是查询提示(hint),必须紧跟在 FROM 子句的表名之后、WHERE 之前。它只对单表生效,多表 JOIN 中需对每张表单独指定。
基本写法:
SELECT * FROM t1 FORCE INDEX (idx_name) WHERE ...
-
idx_name必须是该表上真实存在的索引名,大小写敏感(取决于系统变量lower_case_table_names) - 不能用表达式或列名代替索引名,比如
FORCE INDEX (created_at)是非法的 - 如果索引名含特殊字符或为保留字,要用反引号包裹:
FORCE INDEX (`order_status_idx`) - 可以同时指定多个索引:
FORCE INDEX (idx_a, idx_b),但优化器仍只选其一,不会合并使用
为什么 EXPLAIN 显示用了索引,但实际执行还是慢
常见错觉:看到 EXPLAIN 的 key 列非 NULL 就以为走对了索引。其实 FORCE INDEX 只强制“使用该索引”,不保证“高效使用”。比如:
- 索引列在
WHERE条件中未做最左前缀匹配,导致全索引扫描(type: index) - 索引选择性差(如布尔字段、大量重复值),MySQL 认为回表成本高于全表扫描,
FORCE INDEX会强行绕过这个判断,反而更慢 - 查询涉及
ORDER BY或LIMIT,而强制的索引不覆盖排序需求,触发 filesort
验证方法:加 EXPLAIN FORMAT=JSON,重点看 used_key_parts 和 rows_examined_per_scan 是否合理。
FORCE INDEX 和 USE INDEX、IGNORE INDEX 的区别
三者都是表级 hint,但行为边界不同:
-
USE INDEX (a,b):告诉优化器“只考虑这些索引”,但它仍可能选NULL(即全表扫描) -
FORCE INDEX (a):告诉优化器“必须用这个索引”,哪怕评估成本更高,也会强制走 —— 这是它和USE INDEX的本质区别 -
IGNORE INDEX (c):仅排除指定索引,其他索引照常参与评估 - 三者可共存,但
FORCE INDEX优先级最高;若同时写FORCE INDEX (a) IGNORE INDEX (a),MySQL 会报语法错误
哪些场景下 FORCE INDEX 真的有用
它不是调优首选,而是兜底手段。真正值得用的情况极少,典型有:
- 统计类慢查询中,优化器误判数据分布(例如新导入数据后未
ANALYZE TABLE),导致跳过高选择性索引 - 分区表中,优化器未能正确裁剪分区,配合
FORCE INDEX可间接引导分区选择(需索引建在分区键上) - 调试阶段验证某索引的实际性能边界,比如对比
FORCE INDEX (primary)和FORCE INDEX (idx_time)的rows和filtered - 应用层 ORM 生成的 SQL 固定且无法改写,又必须绕过劣质执行计划时(临时补救)
注意:FORCE INDEX 会抑制索引统计信息更新带来的执行计划自动优化,长期使用可能掩盖底层数据或结构问题。


















