索引提示为优化器提供了关于如何在查询处理中选择索引的信息。索引提示,描述在这里,不同于优化器提示,描述在第 10.9.3 节,“优化器提示”。索引和优化器提示可以单独或一起使用。
索引提示适用于SELECT
和UPDATE
语句。它们也适用于多表DELETE
语句,但不适用于单表DELETE,如本节后面所示。
索引提示在表名后指定。(对于SELECT
语句的表名语法,见第 15.2.13.2 节,“JOIN 子句”。)索引提示的语法如下所示:
tbl_name [[AS] alias] [index_hint_list]
index_hint_list:
index_hint [index_hint] ...
index_hint:
USE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
| {IGNORE|FORCE} {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
index_list:
index_name [, index_name] ...
The USE INDEX (
提示告诉 MySQL 只使用命名的索引来查找表中的行。备用语法 index_list
)IGNORE INDEX (
告诉 MySQL 不使用某些特定的索引或索引。这些提示非常有用,如果index_list
)EXPLAIN
显示 MySQL 正在使用错误的索引从可能的索引列表中。
The FORCE INDEX
提示类似于 USE INDEX (
,只是添加了一个假设,即表扫描非常昂贵。换言之,表扫描仅在无法使用命名的索引来查找表中的行时使用。index_list
)
MySQL 8.3 支持索引级优化器提示JOIN_INDEX
、GROUP_INDEX
、ORDER_INDEX
和INDEX
,它们等同于和旨在取代FORCE INDEX
索引提示,以及NO_JOIN_INDEX
、NO_GROUP_INDEX
、NO_ORDER_INDEX
和NO_INDEX
优化器提示,旨在取代IGNORE INDEX
索引提示。因此,您可以期望USE INDEX
、FORCE INDEX
和IGNORE INDEX
在未来 MySQL 版本中弃用,并在某个时候完全删除。
这些索引级优化器提示支持单表和多表DELETE
语句。
有关更多信息,见索引级优化器提示。
每个提示都需要索引名称,而不是列名称。要引用主键,使用名称 PRIMARY
。要查看表的索引名称,使用SHOW INDEX
语句或信息模式STATISTICS
表。
一个 index_name
值不需要是完整的索引名称。它可以是索引名称的不ambiguous 前缀。如果前缀是ambiguous,会出现错误。
示例:
SELECT * FROM table1 USE INDEX (col1_index,col2_index)
WHERE col1=1 AND col2=2 AND col3=3;
SELECT * FROM table1 IGNORE INDEX (col3_index)
WHERE col1=1 AND col2=2 AND col3=3;
索引提示的语法具有以下特征:
-
语法上,
USE INDEX
可以省略index_list
,这意味着“不使用任何索引”。省略index_list
对于FORCE INDEX
或IGNORE INDEX
是语法错误。 -
您可以通过添加
FOR
子句来指定索引提示的范围,这提供了对优化器选择执行计划的更多控制权。要影响 MySQL 决定如何在表中查找行和处理连接的索引使用,请使用FOR JOIN
。要影响排序或分组行的索引使用,请使用FOR ORDER BY
或FOR GROUP BY
。 -
您可以指定多个索引提示:
SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a;
在同一个提示中(甚至在同一个提示中)命名相同的索引不是错误:
SELECT * FROM t1 USE INDEX (i1) USE INDEX (i1,i1);
但是,混合使用
USE INDEX
和FORCE INDEX
对于同一个表是错误的:SELECT * FROM t1 USE INDEX FOR JOIN (i1) FORCE INDEX FOR JOIN (i2);
如果索引提示不包含 FOR
子句,则该提示的范围将应用于语句的所有部分。例如,该提示:
IGNORE INDEX (i1)
等同于以下组合的提示:
IGNORE INDEX FOR JOIN (i1)
IGNORE INDEX FOR ORDER BY (i1)
IGNORE INDEX FOR GROUP BY (i1)
在 MySQL 5.0 中,如果没有 FOR
子句,索引提示的范围将仅应用于行检索。要使服务器在没有 FOR
子句时使用旧行为,请在服务器启动时启用 old
系统变量。在复制设置中启用该变量时请小心,以免导致复制错误。
当索引提示被处理时,它们将根据类型(USE
、FORCE
、IGNORE
)和范围(FOR JOIN
、FOR ORDER BY
、FOR GROUP BY
)收集到单个列表中。例如:
SELECT * FROM t1
USE INDEX () IGNORE INDEX (i2) USE INDEX (i1) USE INDEX (i2);
等同于:
SELECT * FROM t1
USE INDEX (i1,i2) IGNORE INDEX (i2);
然后,索引提示将按照以下顺序应用于每个范围:
-
{USE|FORCE} INDEX
如果存在则应用。(如果不存在,则使用优化器确定的索引集。) -
IGNORE INDEX
将应用于前一步的结果上。例如,以下两个查询是等同的:SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX (i2) USE INDEX (i2); SELECT * FROM t1 USE INDEX (i1);
对于 FULLTEXT
搜索,索引提示的工作方式如下:
-
对于自然语言模式搜索,索引提示将被默默忽略。例如,
IGNORE INDEX(i1)
将被忽略,且不发出警告,索引仍将被使用。 -
对于布尔模式搜索,索引提示带有
FOR ORDER BY
或FOR GROUP BY
将被默默忽略。索引提示带有FOR JOIN
或无FOR
修饰符将被尊重。与非FULLTEXT
搜索不同的是,提示将用于查询执行的所有阶段(查找行、检索、分组和排序)。这甚至适用于非FULLTEXT
索引的提示。例如,以下两个查询是等同的:
SELECT * FROM t USE INDEX (index1) IGNORE INDEX FOR ORDER BY (index1) IGNORE INDEX FOR GROUP BY (index1) WHERE ... IN BOOLEAN MODE ... ; SELECT * FROM t USE INDEX (index1) WHERE ... IN BOOLEAN MODE ... ;
索引提示也适用于 DELETE
语句,但仅当您使用多表 DELETE
语法,如下所示:
mysql> EXPLAIN DELETE FROM t1 USE INDEX(col2)
-> WHERE col1 BETWEEN 1 AND 100 AND COL2 BETWEEN 1 AND 100\G
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'use
index(col2) where col1 between 1 and 100 and col2 between 1 and 100' at line 1
mysql> EXPLAIN DELETE t1.* FROM t1 USE INDEX(col2)
-> WHERE col1 BETWEEN 1 AND 100 AND COL2 BETWEEN 1 AND 100\G
*************************** 1. row ***************************
id: 1
select_type: DELETE
table: t1
partitions: NULL
type: range
possible_keys: col2
key: col2
key_len: 5
ref: NULL
rows: 72
filtered: 11.11
Extra: Using where
1 row in set, 1 warning (0.00 sec)