索引提示解决什么问题
优化器按统计信息估算成本来选择索引与连接顺序,统计失真、条件相关性强或索引基数偏差时就会挑错。USE / IGNORE / FORCE INDEX 把单表的候选索引收窄或指定,STRAIGHT_JOIN 固定多表连接的驱动顺序。它们的本质是把「当前数据分布下的经验」写进 SQL、绕过优化器判断,属于排障兜底而非常态写法。
基本信息
| 适用平台 | MySQL 5.7 / 8.0;InnoDB 与 MyISAM 均支持 |
|---|---|
| 索引提示位置 | 表名之后紧跟 USE|IGNORE|FORCE INDEX (idx1, idx2) |
| 连接顺序 | SELECT STRAIGHT_JOIN 写在关键字后,按书写顺序连接 |
| 提示粒度 | 只能限定候选索引,不能指定扫描方向与范围 |
| 替代写法 | 8.0 语句级优化器提示 /*+ JOIN_ORDER / NO_INDEX */ |
| 验证方式 | EXPLAIN 看实际选用的 key 与访问类型 type |
典型使用场景
- 线上慢查询因统计未更新走了全表扫描,用 FORCE INDEX 抢修并保留复盘记录
- 范围加排序的查询被误判,强制命中覆盖索引避免大量回表
- 深翻页或参数相关性强查询需要稳定计划,避免不同参数下计划漂移
- 多表连接时小表被当成驱动表导致回表暴涨,用 STRAIGHT_JOIN 固定顺序
- 索引正在灰度上线,先用提示验证收益再决定是否固化到代码
用法示例
用法示例
# 强制走覆盖索引,避免回表
SELECT id, status FROM orders FORCE INDEX (idx_status_created)
WHERE status = 'paid' AND created_at >= '2026-09-01';
# 排除被优化器误选的低选择度索引
SELECT * FROM orders IGNORE INDEX (idx_type) WHERE user_id = 42;
# 固定连接顺序:过滤后行数最少的表做驱动表
SELECT o.id, u.name FROM orders o STRAIGHT_JOIN users u
ON u.id = o.user_id WHERE o.status = 'paid';
# 8.0 语句级提示,作用范围只在这条语句
SELECT /*+ JOIN_ORDER(o, u) */ o.id
FROM orders o JOIN users u ON u.id = o.user_id;
# 确认提示是否生效
EXPLAIN SELECT id FROM orders FORCE INDEX (idx_status_created) WHERE status = 'paid';三种索引提示对比
| 提示或写法 | 语义 | 适用场景 |
|---|---|---|
| USE INDEX | 只在给定索引集合里挑,仍由优化器决定 | 候选索引都可用时收窄范围 |
| IGNORE INDEX | 把指定索引排除出候选集 | 某索引统计失真被误选 |
| FORCE INDEX | 等价 USE INDEX,并认为全表扫描代价很高 | 必须避免全表扫描 |
| STRAIGHT_JOIN | 按书写顺序连接,禁止重排 | 连接顺序错导致回表暴涨 |
| /*+ JOIN_ORDER */ | 语句级提示,只影响这一条语句 | 不想改结构就干预连接顺序 |
| USE INDEX (PRIMARY) | 显式限定只用主键 | 强制主键范围扫描 |
提示是否生效取决于索引是否存在、语法是否正确,以及优化器还有没有别的合法路径:FORCE INDEX 只保证不走全表扫描,仍可能换用集合里的另一个索引。上线前后都用 EXPLAIN 核对 key、type、rows,别凭感觉判断。