Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

10.9.4 索引提示

索引提示为优化器提供了关于如何在查询处理中选择索引的信息。索引提示,描述在这里,不同于优化器提示,描述在第 10.9.3 节,“优化器提示”。索引和优化器提示可以单独或一起使用。

索引提示适用于SELECTUPDATE语句。它们也适用于多表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 (index_list) 提示告诉 MySQL 只使用命名的索引来查找表中的行。备用语法 IGNORE INDEX (index_list) 告诉 MySQL 不使用某些特定的索引或索引。这些提示非常有用,如果EXPLAIN 显示 MySQL 正在使用错误的索引从可能的索引列表中。

The FORCE INDEX 提示类似于 USE INDEX (index_list),只是添加了一个假设,即表扫描非常昂贵。换言之,表扫描仅在无法使用命名的索引来查找表中的行时使用。

Note

MySQL 8.3 支持索引级优化器提示JOIN_INDEXGROUP_INDEXORDER_INDEXINDEX,它们等同于和旨在取代FORCE INDEX 索引提示,以及NO_JOIN_INDEXNO_GROUP_INDEXNO_ORDER_INDEXNO_INDEX 优化器提示,旨在取代IGNORE INDEX 索引提示。因此,您可以期望USE INDEXFORCE INDEXIGNORE 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 INDEXIGNORE INDEX 是语法错误。

  • 您可以通过添加 FOR 子句来指定索引提示的范围,这提供了对优化器选择执行计划的更多控制权。要影响 MySQL 决定如何在表中查找行和处理连接的索引使用,请使用 FOR JOIN。要影响排序或分组行的索引使用,请使用 FOR ORDER BYFOR 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 INDEXFORCE 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 系统变量。在复制设置中启用该变量时请小心,以免导致复制错误。

当索引提示被处理时,它们将根据类型(USEFORCEIGNORE)和范围(FOR JOINFOR ORDER BYFOR 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);

然后,索引提示将按照以下顺序应用于每个范围:

  1. {USE|FORCE} INDEX 如果存在则应用。(如果不存在,则使用优化器确定的索引集。)

  2. 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 BYFOR 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)