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

MySQL 8.3 Reference Manual  /  ...  /  Invisible Indexes

10.3.12 不可见索引

MySQL 支持不可见索引,即不被优化器使用的索引。该功能适用于主键以外的索引(无论是显式还是隐式的)。

索引默认是可见的。要显式控制新索引的可见性,可以在 CREATE TABLECREATE INDEXALTER TABLE 语句中使用 VISIBLEINVISIBLE 关键字:

CREATE TABLE t1 (
  i INT,
  j INT,
  k INT,
  INDEX i_idx (i) INVISIBLE
) ENGINE = InnoDB;
CREATE INDEX j_idx ON t1 (j) INVISIBLE;
ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;

要更改现有索引的可见性,可以使用 VISIBLEINVISIBLE 关键字与 ALTER TABLE ... ALTER INDEX 操作:

ALTER TABLE t1 ALTER INDEX i_idx INVISIBLE;
ALTER TABLE t1 ALTER INDEX i_idx VISIBLE;

Information Schema STATISTICS 表或 SHOW INDEX 输出中提供了索引是否可见的信息。例如:

mysql> SELECT INDEX_NAME, IS_VISIBLE
       FROM INFORMATION_SCHEMA.STATISTICS
       WHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 't1';
+------------+------------+
| INDEX_NAME | IS_VISIBLE |
+------------+------------+
| i_idx      | YES        |
| j_idx      | NO         |
| k_idx      | NO         |
+------------+------------+

不可见索引使得可以测试删除索引对查询性能的影响,而不需要进行破坏性更改。如果索引实际上是需要的或被优化器使用,那么可以通过以下方式注意到其缺失对查询的影响:

包含索引提示的查询将出错。

  • 性能模式数据显示受影响的查询的工作负载增加。

  • 查询的 EXPLAIN 执行计划不同。

  • 查询出现在慢查询日志中,而之前没有出现。

  • optimizer_switch 系统变量的 use_invisible_indexes 标志控制优化器是否使用不可见索引来构建查询执行计划。如果标志为 off(默认),优化器将忽略不可见索引(与引入该标志之前的行为相同)。如果标志为 on,不可见索引将保持不可见,但优化器将其考虑在内以构建执行计划。

使用 SET_VAR 优化器提示可以临时更新 optimizer_switch 的值,以便在单个查询中启用不可见索引,例如:

索引可见性不影响索引维护。例如,索引继续根据表行的更改而更新,并且唯一索引继续阻止列中的重复插入,无论索引是否可见。

mysql> EXPLAIN SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */
     >     i, j FROM t1 WHERE j >= 50\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: j_idx
          key: j_idx
      key_len: 5
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: Using index condition

mysql> EXPLAIN SELECT i, j FROM t1 WHERE j >= 50\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5
     filtered: 33.33
        Extra: Using where

如果表没有明确的主键,但有唯一索引在 NOT NULL 列上,那么该索引将对表行施加同样的约束,如同明确的主键一样,并且该索引不能被设为不可见。考虑以下表定义:

定义中没有明确的主键,但索引在 NOT NULL 列 j 上施加了同样的约束,如同主键一样,该索引不能被设为不可见:

CREATE TABLE t2 (
  i INT NOT NULL,
  j INT NOT NULL,
  UNIQUE j_idx (j)
) ENGINE = InnoDB;

现在假设明确的主键被添加到表中:

mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;
ERROR 3522 (HY000): A primary key index cannot be invisible.

明确的主键不能被设为不可见。此外,唯一索引在 j 上不再作为隐式主键,并且可以被设为不可见:

ALTER TABLE t2 ADD PRIMARY KEY (i);

The explicit primary key cannot be made invisible. In addition, the unique index on j no longer acts as an implicit primary key and as a result can be made invisible:

mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;
Query OK, 0 rows affected (0.03 sec)