天天看點

MySQL 索引使用詳解—官方原版

一種資料結構,通常通過形成表示特定列或列集合的所有值的樹結構(B樹),為表的行提供快速查找功能。

InnoDB表總是有一個表示主鍵的聚集索引。它們還可以在一列或多列上定義一個或多個輔助索引。根據其結構,二級索引可以分為部分索引、列索引或複合索引。

索引用于快速查找具有特定列值的行。如果沒有索引,MySQL必須從第一行開始,然後讀取整個表以查找相關行。表越大,成本就越高。如果表中有相關列的索引,MySQL可以快速确定要在資料檔案中間查找的位置,而無需檢視所有資料。這比按順序讀取每一行快得多。

MySQL索引類型如下:

(1) 從索引存儲結構劃分:B Tree索引、Hash索引、

(2) 從應用層次劃分:普通索引、唯一索引、主鍵索引、複合索引、FULLTEXT全文索引

(3) 從索引鍵值類型劃分:主鍵索引、二級索引(部分索引、列索引或複合索引);

(4) 從資料存儲和索引鍵值邏輯關系劃分:聚集索引(聚簇索引)、非聚集索引(非聚簇索引);

CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name
    [index_type]
    ON tbl_name (key_part,...)
    [index_option]
    [algorithm_option | lock_option] ...

key_part: {col_name [(length)] | (expr)} [ASC | DESC]

index_option: {
    KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'
  | {VISIBLE | INVISIBLE}
  | ENGINE_ATTRIBUTE [=] 'string'
  | SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
}

index_type:
    USING {BTREE | HASH}

algorithm_option:
    ALGORITHM [=] {DEFAULT | INPLACE | COPY}

lock_option:
    LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}           

一、主鍵索引

它是一種特殊的唯一索引,不允許有空值。在建立或修改表時追加主鍵限制即可,每個表隻能有一個主鍵。

建立主鍵索引的方法如下:

CREATETABLE tablename ( [...], PRIMARYKEY (字段名) );
ALTERTABLE tablename ADDPRIMARYKEY (字段名);           

二、唯一索引

UNIQUE索引建立一個限制,使得索引中的所有值都必須不同。如果嘗試添加具有與現有行比對的鍵值的新行,則會發生錯誤。如果為UNIQUE索引中的列指定字首值,則列值在字首長度内必須是唯一的。UNIQUE索引允許包含NULL的列具有多個NULL值。

如果表的PRIMARY KEY或UNIQUE NOT NULL索引由一個整數類型的列組成,則可以使用_rowid引用SELECT語句中的索引列,如下所示:

  • 如果存在由單個整數列組成的PRIMARY KEY,則rowid引用PRIMARY KEY列。如果存在PRIMARY KEY,但它不包含單個整數列,則不能使用_rowid。
  • 否則,_rowid引用第一個UNIQUE NOT NULL索引中的列(如果該索引由單個整數列組成)。如果第一個UNIQUE NOT NULL索引不包含單個整數列,則不能使用_rowid。

三、全文索引

FULLTEXT索引僅支援InnoDB和MyISAM表,并且隻能包含CHAR、VARCHAR和TEXT列。索引總是在整個列上進行;不支援列字首索引,如果指定,則忽略任何字首長度

1、InnoDB全文索引設計

InnoDB全文索引具有倒排 索引設計。反向索引存儲單詞清單,并且 每個單詞,該單詞出現在其中的文檔清單。自 支援鄰近搜尋,每個單詞的位置資訊是 也存儲為位元組偏移量。

2、InnoDB 全文索引表

建立全文索引時,建立索引表集,如下所示 例:InnoDB

mysql> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200),
       FULLTEXT idx (opening_line)
       ) ENGINE=InnoDB;

mysql> SELECT table_id, name, space from INFORMATION_SCHEMA.INNODB_TABLES
       WHERE name LIKE 'test/%';
+----------+----------------------------------------------------+-------+
| table_id | name                                               | space |
+----------+----------------------------------------------------+-------+
|      333 | test/fts_0000000000000147_00000000000001c9_index_1 |   289 |
|      334 | test/fts_0000000000000147_00000000000001c9_index_2 |   290 |
|      335 | test/fts_0000000000000147_00000000000001c9_index_3 |   291 |
|      336 | test/fts_0000000000000147_00000000000001c9_index_4 |   292 |
|      337 | test/fts_0000000000000147_00000000000001c9_index_5 |   293 |
|      338 | test/fts_0000000000000147_00000000000001c9_index_6 |   294 |
|      330 | test/fts_0000000000000147_being_deleted            |   286 |
|      331 | test/fts_0000000000000147_being_deleted_cache      |   287 |
|      332 | test/fts_0000000000000147_config                   |   288 |
|      328 | test/fts_0000000000000147_deleted                  |   284 |
|      329 | test/fts_0000000000000147_deleted_cache            |   285 |
|      327 | test/opening_lines                                 |   283 |
+----------+----------------------------------------------------+-------+           

四、多值索引

從MySQL 8.0.17開始,InnoDB支援多值索引。多值索引是在存儲值數組的列上定義的輔助索引。“正常”索引對每個資料記錄有一個索引記錄(1:1)。多值索引可以針對單個資料記錄(N:1)具有多個索引記錄。多值索引用于索引JSON數組。例如,在以下JSON文檔中的郵政編碼數組上定義的多值索引為每個郵政編碼建立一個索引記錄,每個索引記錄引用相同的資料記錄。

1、建立多值索引

可以在CREATETABLE、ALTERTABLE或CREATEINDEX語句中建立多值索引。這需要在索引定義中使用CAST(…AS…ARRAY),将JSON數組中相同類型的标量值強制轉換為SQL資料類型數組。然後用SQL資料類型數組中的值透明地生成虛拟列;最後,在虛拟列上建立函數索引(也稱為虛拟索引)。它是在SQL資料類型數組的虛拟值列上定義的函數索引,構成了多值索引。

以下清單中的示例顯示了在名為customers的表中的JSON列custinfo上的數組$.zipcode上建立多值索引zip的三種不同方式。在每種情況下,JSON數組都被轉換為一個由UNSIGNED整數值組成的SQL資料類型數組。

CREATE TABLE

CREATE TABLE customers (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    custinfo JSON,
    INDEX zips( (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) )
    );           

CREATE TABLE加:ALTER TABLE

CREATE TABLE customers (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    custinfo JSON
    );

ALTER TABLE customers ADD INDEX zips( (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) );           

CREATE TABLE加:CREATE INDEX

CREATE TABLE customers (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    custinfo JSON
    );

CREATE INDEX zips ON customers ( (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) );           

多值索引也可以定義為複合索引的一部分。此示例顯示了一個複合索引,它包括兩個單值部分(用于id和修改的列)和一個多值部分(對于custinfo列):

CREATE TABLE customers (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    custinfo JSON
    );

ALTER TABLE customers ADD INDEX comp(id, modified,
    (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) );           

複合索引中隻能使用一個多值鍵部分。多值鍵部分可以相對于鍵的其他部分以任何順序使用。換句話說,剛才顯示的ALTERTABLE語句可能使用了comp(id,(CAST(custinfo->'$.zipcode'AS UNSIGNED ARRAY),已修改))(或任何其他排序),并且仍然有效。

2、使用多值索引

當WHERE子句中指定了以下函數時,優化器使用多值索引來擷取記錄:

我們可以通過使用以下CREATETABLE和INSERT語句建立和填充customers表來示範這一點:

mysql> CREATE TABLE customers (
    ->     id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    ->     custinfo JSON
    ->     );
Query OK, 0 rows affected (0.51 sec)

mysql> INSERT INTO customers VALUES
    ->     (NULL, NOW(), '{"user":"Jack","user_id":37,"zipcode":[94582,94536]}'),
    ->     (NULL, NOW(), '{"user":"Jill","user_id":22,"zipcode":[94568,94507,94582]}'),
    ->     (NULL, NOW(), '{"user":"Bob","user_id":31,"zipcode":[94477,94507]}'),
    ->     (NULL, NOW(), '{"user":"Mary","user_id":72,"zipcode":[94536]}'),
    ->     (NULL, NOW(), '{"user":"Ted","user_id":56,"zipcode":[94507,94582]}');
Query OK, 5 rows affected (0.07 sec)
Records: 5  Duplicates: 0  Warnings: 0           

首先,我們對customers表執行三個查詢,每個查詢使用MEMBER OF()、JSON_CONTAINS()和JSON_OVERLAPS(),每個查詢的結果如下所示:

mysql> SELECT * FROM customers
    ->     WHERE 94507 MEMBER OF(custinfo->'$.zipcode');
+----+---------------------+-------------------------------------------------------------------+
| id | modified            | custinfo                                                          |
+----+---------------------+-------------------------------------------------------------------+
|  2 | 2019-06-29 22:23:12 | {"user": "Jill", "user_id": 22, "zipcode": [94568, 94507, 94582]} |
|  3 | 2019-06-29 22:23:12 | {"user": "Bob", "user_id": 31, "zipcode": [94477, 94507]}         |
|  5 | 2019-06-29 22:23:12 | {"user": "Ted", "user_id": 56, "zipcode": [94507, 94582]}         |
+----+---------------------+-------------------------------------------------------------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM customers
    ->     WHERE JSON_CONTAINS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+----+---------------------+-------------------------------------------------------------------+
| id | modified            | custinfo                                                          |
+----+---------------------+-------------------------------------------------------------------+
|  2 | 2019-06-29 22:23:12 | {"user": "Jill", "user_id": 22, "zipcode": [94568, 94507, 94582]} |
|  5 | 2019-06-29 22:23:12 | {"user": "Ted", "user_id": 56, "zipcode": [94507, 94582]}         |
+----+---------------------+-------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM customers
    ->     WHERE JSON_OVERLAPS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+----+---------------------+-------------------------------------------------------------------+
| id | modified            | custinfo                                                          |
+----+---------------------+-------------------------------------------------------------------+
|  1 | 2019-06-29 22:23:12 | {"user": "Jack", "user_id": 37, "zipcode": [94582, 94536]}        |
|  2 | 2019-06-29 22:23:12 | {"user": "Jill", "user_id": 22, "zipcode": [94568, 94507, 94582]} |
|  3 | 2019-06-29 22:23:12 | {"user": "Bob", "user_id": 31, "zipcode": [94477, 94507]}         |
|  5 | 2019-06-29 22:23:12 | {"user": "Ted", "user_id": 56, "zipcode": [94507, 94582]}         |
+----+---------------------+-------------------------------------------------------------------+
4 rows in set (0.00 sec)           

接下來,我們對前面三個查詢中的每一個運作EXPLAIN:

mysql> EXPLAIN SELECT * FROM customers
    ->     WHERE 94507 MEMBER OF(custinfo->'$.zipcode');
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM customers
    ->     WHERE JSON_CONTAINS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM customers
    ->     WHERE JSON_OVERLAPS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)           

剛才顯示的三個查詢都不能使用任何鍵。為了解決這個問題,我們可以在JSON列(custinfo)中的zipcode數組上添加一個多值索引,如下所示:

mysql> ALTER TABLE customers
    ->     ADD INDEX zips( (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) );
Query OK, 0 rows affected (0.47 sec)
Records: 0  Duplicates: 0  Warnings: 0           

當我們再次運作前面的EXPLAIN語句時,我們現在可以觀察到查詢可以(并且确實)使用剛剛建立的索引zip:

mysql> EXPLAIN SELECT * FROM customers
    ->     WHERE 94507 MEMBER OF(custinfo->'$.zipcode');
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | ref  | zips          | zips | 9       | const |    1 |   100.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM customers
    ->     WHERE JSON_CONTAINS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | range | zips          | zips | 9       | NULL |    6 |   100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM customers
    ->     WHERE JSON_OVERLAPS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | customers | NULL       | range | zips          | zips | 9       | NULL |    6 |   100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)           

多值索引可以定義為唯一鍵。如果定義為唯一鍵,則嘗試插入多值索引中已存在的值将傳回重複鍵錯誤。如果已經存在重複值,則嘗試添加唯一的多值索引失敗,如下所示:

mysql> ALTER TABLE customers DROP INDEX zips;
Query OK, 0 rows affected (0.55 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE customers
    ->     ADD UNIQUE INDEX zips((CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)));
ERROR 1062 (23000): Duplicate entry '[94507, ' for key 'customers.zips'
mysql> ALTER TABLE customers
    ->     ADD INDEX zips((CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)));
Query OK, 0 rows affected (0.36 sec)
Records: 0  Duplicates: 0  Warnings: 0           

3、多值指數的特征

多值索引具有列出的附加特征 這裡:

  • 處理影響多值索引的 DML 操作 與影響正常 DML 操作的方式相同 索引,唯一的差別是可能有更多 對單個聚集索引進行一次插入或更新 記錄。
  • 可為空性和多值索引:
  • 如果多值鍵部分具有空數組,則 no 條目被添加到索引中,資料記錄是 無法通過索引掃描通路。
  • 如果多值鍵部件生成傳回值,則包含的單個條目将添加到多值 指數。如果将關鍵部件定義為 ,則會報告錯誤。NULLNULLNOT NULL
  • 如果類型化數組列設定為 ,則存儲引擎将存儲 包含該内容的單個記錄 指向資料記錄。NULLNULL
  • JSON中不允許空值 索引數組。如果任何傳回值為 ,則将其視為 JSON 空值 和無效的 JSON 值錯誤 被報道。NULL
  • 因為多值索引是虛拟上的虛拟索引 列,它們必須遵守與輔助相同的規則 虛拟生成的列上的索引。
  • 不會為空數組添加索引記錄。

4、多值索引的限制和限制

多值索引受限制和 此處列出的限制:

每個多值索引隻允許一個多值鍵部分。然而,CAST(…AS…ARRAY)表達式可以引用JSON文檔中的多個數組,如下所示:

CAST(data->'$.arr[*][*]' AS UNSIGNED ARRAY)           
  • 在這種情況下,與 JSON 表達式比對的所有值都是 作為單個平面數組存儲在索引中。
  • 具有多值鍵部分的索引不支援 排序,是以不能用作主鍵。為 同樣的原因,無法定義多值索引 使用 or 關鍵字。ASCDESC
  • 多值索引不能是覆寫索引。
  • 多值每條記錄的最大值數 索引由可以存儲的資料量決定 在單個撤消日志頁面上,即 65221 位元組(64K 減去 開銷為 315 位元組),這意味着最大總數 鍵值的長度也是 65221 位元組。最大數量 鍵取決于各種因素,這阻止了定義 特定限制。測試顯示多值索引 例如,每條記錄允許多達 1604 個整數鍵。 達到限制時,出現類似于以下内容的錯誤 已報告:錯誤 3905 (HY000):超出最大值 多值索引“IDX”每條記錄的值數由 1 個值。
  • 允許的唯一表達式類型 多值鍵部分是一個表達式。表達式不需要引用現有的 元素插入到索引列中的 JSON 文檔中, 但本身必須在文法上有效。JSON
  • 因為同一聚集索引記錄的索引記錄 分散在多值索引中,a 多值索引不支援範圍掃描或 僅索引掃描。
  • 外鍵中不允許使用多值索引 規格。
  • 不能為多值索引定義索引字首。
  • 不能在資料上将多值索引定義為(請參閱說明 的 函數)。
  • 不支援線上建立多值索引,這意味着該操作使用ALGORITHM=COPY。

以下兩個以外的字元集和排序規則 字元集和歸類的組合不是 支援多值索引:

    • 具有預設二進制排序規則的二進制字元集
    • 使用預設的utf8mb4_0900_as_cs排序規則設定的utf8mb4字元集。
  • 與InnoDB表列上的其他索引一樣,不能使用USING HASH建立多值索引;嘗試這樣做會導緻警告:此存儲引擎不支援HASH索引算法,而是使用存儲引擎預設值。(通常支援使用BTREE。)

五、空間索引

MyISAM、InnoDB、NDB和ARCHIVE存儲引擎支援POINT和GEOMETRY等空間列。(第11.4節“空間資料類型”描述了空間資料類型。)然而,對空間列索引的支援因引擎而異。根據以下規則,空間列上的空間索引和非空間索引可用。

空間列上的空間索引具有以下特征:

    • 僅适用于InnoDB和MyISAM表。為其他存儲引擎指定SPATIAL INDEX會導緻錯誤。
    • 從MySQL 8.0.12開始,空間列上的索引必須是spatial索引。是以,SPATIAL關鍵字是可選的,但對于在空間列上建立索引是隐式的。
    • 僅适用于單個空間列。無法在多個空間列上建立空間索引。
    • 索引列必須為NOT NULL。
    • 禁止使用列字首長度。每一列的全寬被索引。
    • 不允許用于主鍵或唯一索引。

空間列上的非空間索引(使用INDEX、UNIQUE或PRIMARY KEY建立)具有以下特征:

    • 允許用于除ARCHIVE之外的任何支援空間列的存儲引擎。
    • 除非索引是主鍵,否則列可以為NULL。
    • 非空間索引的索引類型取決于存儲引擎。目前使用B樹。
    • 隻允許InnoDB、MyISAM和MEMORY表具有NULL值的列。

六、降序索引

MySQL支援降序索引:索引定義中的DESC不再被忽略,而是按降序存儲鍵值。以前,可以按相反的順序掃描索引,但會降低性能。可以按正向順序掃描降序索引,這樣效率更高。當最有效的掃描順序混合了某些列的升序和其他列的降序時,降序索引也使優化器可以使用多個列索引。

考慮以下表定義,其中包含兩列和四個兩列索引定義,用于列上的各種升序和降序索引組合:

CREATE TABLE t (
  c1 INT, c2 INT,
  INDEX idx1 (c1 ASC, c2 ASC),
  INDEX idx2 (c1 ASC, c2 DESC),
  INDEX idx3 (c1 DESC, c2 ASC),
  INDEX idx4 (c1 DESC, c2 DESC)
);           

表定義産生四個不同的索引。優化器可以對每個ORDERBY子句執行前向索引掃描,無需使用檔案排序操作:

ORDER BY c1 ASC, c2 ASC    -- optimizer can use idx1
ORDER BY c1 DESC, c2 DESC  -- optimizer can use idx4
ORDER BY c1 ASC, c2 DESC   -- optimizer can use idx2
ORDER BY c1 DESC, c2 ASC   -- optimizer can use idx3           

使用降序索引受以下條件限制:

  • 隻有InnoDB存儲引擎支援降序索引,但有以下限制:
    • 如果索引包含降序索引鍵列或主鍵包含降序索引列,則輔助索引不支援更改緩沖。
    • InnoDB SQL解析器不使用降序索引。對于InnoDB全文搜尋,這意味着索引表的FTS_DOC_ID列上所需的索引不能定義為降序索引。
  • 所有可以使用升序索引的資料類型都支援降序索引。
  • 普通(非生成)列和生成列(VIRTUAL和STORED)都支援降序索引。
  • DISTINCT可以使用包含比對列的任何索引,包括降序鍵部分。
  • 具有降序鍵部分的索引不用于調用聚合函數但沒有GROUP BY子句的查詢的MIN()/MAX()優化。
  • BTREE支援降序索引,但不支援HASH索引。FULLTEXT或SPATIAL索引不支援降序索引。
  • 為HASH、FULLTEXT和SPATIAL索引顯式指定ASC和DESC訓示符會導緻錯誤。

您可以在EXPLAIN輸出的Extra列中看到,優化器能夠使用遞減索引,如下所示:

mysql> CREATE TABLE t1 (
    -> a INT, 
    -> b INT, 
    -> INDEX a_desc_b_asc (a DESC, b ASC)
    -> );

mysql> EXPLAIN SELECT * FROM t1 ORDER BY a ASC\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: index
possible_keys: NULL
          key: a_desc_b_asc
      key_len: 10
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Backward index scan; Using index           

在EXPLAIN FORMAT=TREE輸出中,通過在索引名稱後面添加(反向)來訓示降序索引的使用,如下所示:

mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 ORDER BY a ASC\G 
*************************** 1. row ***************************
EXPLAIN: -> Index scan on t1 using a_desc_b_asc (reverse)  (cost=0.35 rows=1)           

大家好,我是Doker品牌的Sinbad,歡迎點贊和評論,您的鼓勵是我們持續更新的動力!更多資料請前往Doker 多克

繼續閱讀