文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  使用索引擴展

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_switch 系統變數的 use_index_extensions 旗標允許控制最佳化工具在判斷如何使用 InnoDB 資料表的次要索引時,是否考慮主鍵資料行。預設情況下,會啟用 use_index_extensions。若要檢查停用索引擴展的使用是否可以提高效能,請使用此陳述式

SET optimizer_switch = 'use_index_extensions=off';

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