原創: 楊濤濤mysql
MySQL 8.0 實現了索引的隱藏屬性。固然這個特性不少商業數據庫早就有了,好比ORACLE,在11g中就實現了。我來介紹下這個小特性。sql
INVISIBLE INDEX,不可見索引或者叫隱藏索引。就是對優化器不可見,查詢的時候優化器不會把她做爲備選。數據庫
其實之前要想完全不可見,只能用開銷較大的drop index;如今有了新的方式,能夠改變索引的屬性,讓其不可見,這一操做只更改metadata,開銷很是小。測試
我大概描述下有可能使用隱藏索引的場景:優化
1. 好比,我有張表t1,原本已經有索引idxf1,idxf2,idxf3。我經過數據字典檢索到idxf3基本沒有使用過,那我是否是能夠判斷這個索引直接刪掉就行了?那若是刪掉後忽然有新上的業務要大量使用呢?難道我要頻繁的drop index/add index嗎?這個時候選擇開銷比較小的隱藏索引就行了。spa
2. 個人業務只有一個可能每月固定執行一次的SQL用到這個索引,那選擇隱藏索引太合適不過了。code
3. 又或者是我想要測試下新建索引對我整個業務的影響程度。若是我直接建新索引,那我既有業務涉及到這個字段的有可能會收到很大影響。那這個時候隱藏索引也是很是合適的。索引
下面我來簡單舉例如何使用隱藏索引:ci
表結構it
mysql> create table f1 (id serial primary key, f1 int,f2 int ); Query OK, 0 rows affected (0.11 sec)
建立兩個索引,默承認見。
索引1,
mysql> alter table f1 add key idx_f1(f1), add key idx_f2(f2); Query OK, 0 rows affected (0.12 sec) Records: 0 Duplicates: 0 Warnings: 0
索引2,
mysql> show create table f1\G *************************** 1. row *************************** Table: f1 Create Table: CREATE TABLE `f1` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `f1` int(11) DEFAULT NULL, `f2` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`), KEY `idx_f1` (`f1`), KEY `idx_f2` (`f2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
簡單寫個造數據的存儲過程。
DELIMITER $$ USE `ytt`$$ CREATE PROCEDURE `sp_generate_data_f1`( IN f_cnt INT ) BEGIN DECLARE i,j INT DEFAULT 0; SET @@autocommit=0; WHILE i < f_cnt DO SET i = i + 1; IF j = 100 THEN SET j = 0; COMMIT; END IF; SET j = j + 1; INSERT INTO f1 (f1,f2) SELECT CEIL(RAND()*100),CEIL(RAND()*100); END WHILE; COMMIT; SET @@autocommit=1; END$$ DELIMITER ;
生成1W條記錄
mysql> call sp_generate_data_f1(10000); Query OK, 0 rows affected (5.42 sec)
咱們把f2列上的索引變爲不可見,結果瞬間完成。
mysql> alter table f1 alter index idx_f2 invisible; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0
在看下錶結構,此時索引標記爲Invisible。
mysql> show create table f1 \G *************************** 1. row *************************** Table: f1 Create Table: CREATE TABLE `f1` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `f1` int(11) DEFAULT NULL, `f2` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`), KEY `idx_f1` (`f1`), KEY `idx_f2` (`f2`) /*!80000 INVISIBLE */ ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
給一條有f2列過濾的SQL, 發現優化器用不到這個索引了。
mysql> explain select count(*) from f1 where f2 = 52\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: f1 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 9991 filtered: 1.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)
用force index 強制使用,直接報錯。
mysql> explain select count(*) from f1 force index (idx_f2) where f2 = 52\G ERROR 1176 (42000): Key 'idx_f2' doesn't exist in table 'f1'
那 MySQL 8.0 的優化器開關裏能夠告訴它,有的時候能夠用隱藏索引。來打開看看。
mysql> set @@optimizer_switch = 'use_invisible_indexes=on'; Query OK, 0 rows affected (0.00 sec)
那這條SQL 如今能夠用idx_f2了。
mysql> explain select count(*) from f1 where f2 = 52\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: f1 partitions: NULL type: ref possible_keys: idx_f2 key: idx_f2 key_len: 5 ref: const rows: 121 filtered: 100.00 Extra: Using index 1 row in set, 1 warning (0.00 sec)
INVISIBLE INDEX 的確是一個頗有用的小特性,給索引增長了第三個額外的開關選項。想要了解更多的建議閱讀MySQL手冊。