文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (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     |
+-----------------------+-------+

系統變數 optimizer_switchuse_index_extensions 旗標允許控制最佳化工具在決定如何使用 InnoDB 資料表的輔助索引時,是否將主鍵欄位納入考量。預設情況下,use_index_extensions 已啟用。要檢查停用索引擴展的使用是否可以提高效能,請使用以下語句:

SET optimizer_switch = 'use_index_extensions=off';

最佳化工具對索引擴展的使用受限於索引中索引鍵部分數量 (16) 和最大索引鍵長度 (3072 位元組) 的一般限制。