文档主页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  索引扩展的使用

10.3.10 索引扩展的使用

InnoDB 自动将每个辅助索引扩展,并在其后附加主键列。考虑这个表定义

CREATE TABLE t1 (
  i1 INT NOT NULL DEFAULT 0,
  i2 INT NOT NULL DEFAULT 0,
  d DATE DEFAULT NULL,
  PRIMARY KEY (i1, i2),
  INDEX k_d (d)
) ENGINE = InnoDB;

此表在列 (i1, i2) 上定义了主键。它还在列 (d) 上定义了一个辅助索引 k_d,但在内部,InnoDB 会扩展此索引,并将其视为列 (d, i1, i2)

优化器在确定如何使用和是否使用该索引时会考虑到扩展辅助索引的主键列。这会导致更有效的查询执行计划和更好的性能。

优化器可以使用扩展的辅助索引进行 refrangeindex_merge 索引访问、松散索引扫描访问、连接和排序优化以及 MIN()/MAX() 优化。

以下示例显示了优化器是否使用扩展的辅助索引如何影响执行计划。假设 t1 使用这些行填充

INSERT INTO t1 VALUES
(1, 1, '1998-01-01'), (1, 2, '1999-01-01'),
(1, 3, '2000-01-01'), (1, 4, '2001-01-01'),
(1, 5, '2002-01-01'), (2, 1, '1998-01-01'),
(2, 2, '1999-01-01'), (2, 3, '2000-01-01'),
(2, 4, '2001-01-01'), (2, 5, '2002-01-01'),
(3, 1, '1998-01-01'), (3, 2, '1999-01-01'),
(3, 3, '2000-01-01'), (3, 4, '2001-01-01'),
(3, 5, '2002-01-01'), (4, 1, '1998-01-01'),
(4, 2, '1999-01-01'), (4, 3, '2000-01-01'),
(4, 4, '2001-01-01'), (4, 5, '2002-01-01'),
(5, 1, '1998-01-01'), (5, 2, '1999-01-01'),
(5, 3, '2000-01-01'), (5, 4, '2001-01-01'),
(5, 5, '2002-01-01');

现在考虑此查询

EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'

执行计划取决于是否使用扩展索引。

当优化器不考虑索引扩展时,它会将索引 k_d 仅视为 (d)EXPLAIN 为查询生成以下结果

mysql> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ref
possible_keys: PRIMARY,k_d
          key: k_d
      key_len: 4
          ref: const
         rows: 5
        Extra: Using where; Using index

当优化器考虑索引扩展时,它会将 k_d 视为 (d, i1, i2)。在这种情况下,它可以使用最左边的索引前缀 (d, i1) 来生成更好的执行计划

mysql> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ref
possible_keys: PRIMARY,k_d
          key: k_d
      key_len: 8
          ref: const,const
         rows: 1
        Extra: Using index

在这两种情况下,key 都表示优化器使用了辅助索引 k_d,但 EXPLAIN 输出显示了使用扩展索引带来的这些改进

  • key_len 从 4 字节变为 8 字节,这表明键查找使用了列 di1,而不仅仅是 d

  • ref 值从 const 变为 const,const,因为键查找使用了两个键部分,而不是一个。

  • rows 计数从 5 降至 1,这表明 InnoDB 应该需要检查更少的行才能生成结果。

  • Extra 值从 Using where; Using index 变为 Using index。这意味着可以使用索引读取行,而无需咨询数据行中的列。

优化器在使用扩展索引方面的行为差异也可以通过 SHOW STATUS 来观察。

FLUSH TABLE t1;
FLUSH STATUS;
SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01';
SHOW STATUS LIKE 'handler_read%'

前面的语句包括 FLUSH TABLESFLUSH STATUS 以刷新表缓存并清除状态计数器。

在没有索引扩展的情况下,SHOW STATUS 生成以下结果

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 1     |
| Handler_read_last     | 0     |
| Handler_read_next     | 5     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+

在有索引扩展的情况下,SHOW STATUS 生成以下结果。 Handler_read_next 值从 5 降至 1,这表明更有效地使用了索引

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 1     |
| Handler_read_last     | 0     |
| Handler_read_next     | 1     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+

use_index_extensionsoptimizer_switch 系统变量的标志,它允许控制优化器在确定如何使用 InnoDB 表的辅助索引时是否考虑主键列。默认情况下,use_index_extensions 处于启用状态。若要检查禁用索引扩展的使用是否可以提高性能,请使用以下语句

SET optimizer_switch = 'use_index_extensions=off';

优化器对索引扩展的使用会受到索引中键部分数量(16 个)和最大键长度(3072 字节)的限制。