1. 程式人生 > >牛逼!MySQL 8.0 中的索引可以隱藏了…

牛逼!MySQL 8.0 中的索引可以隱藏了…

MySQL 8.0 雖然釋出很久了,但可能大家都停留在 5.7.x,甚至更老,其實 MySQL 8.0 新增了許多重磅新特性,比如棧長今天要介紹的 "**隱藏索引**" 或者 "**不可見索引**"。 ## 隱藏索引是什麼鬼? **隱藏索引** 字面意思就是把索引進行隱藏,即不可見,它不是用來查詢優化的,所以它不會被優化器使用到。隱藏索引適用於除主鍵索引(顯示或者隱式設定)之外的索引,意味著主鍵索引是不能通過任何方式隱藏的。 MySQL 資料庫預設建立的索引都是可見的,要顯式控制一個索引的可見性,可以在 CREATE TABLE,CREATE INDEX 或 ALTER TABLE 的索引定義命令中使用 `VISIBLE` 或 `INVISIBLE` 關鍵字。 如下面示例所示: ``` CREATE TABLE javastack ( age INT, weight INT, tall INT, INDEX age_idx (age) INVISIBLE ) ENGINE = InnoDB; CREATE INDEX weight_idx ON javastack (weight) INVISIBLE; ALTER TABLE javastack ADD INDEX tall_idx (tall) INVISIBLE; ``` 要變更現有索引的可見性,可以在 ALTER TABLE ... ALTER INDEX 命令中使用 `VISIBLE` 或 `INVISIBLE` 關鍵字。 **年齡索引變更為不可見(隱藏):** ``` ALTER TABLE javastack ALTER INDEX age_idx INVISIBLE; ``` **年齡索引變更為可見:** ``` ALTER TABLE javastack ALTER INDEX age_idx VISIBLE; ``` 怎麼知道一個表中的索引是可見還是不可見,可以從 INFORMATION_SCHEMA.STATISTICS 表,或者 SHOW INDEX 命令輸出中獲得。例如: ``` mysql> SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 'javastack'; +------------+------------+ | INDEX_NAME | IS_VISIBLE | +------------+------------+ | age_idx | YES | | weight_idx | NO | | tall_idx | NO | +------------+------------+ ``` ## 隱藏索引有什麼用? 從上面隱藏索引介紹我們知道,隱藏索引可以不被優化器所使用,那麼我們可以把某個表的某個索引設定隱藏,然後再測試 SQL 語句的查詢效能。 即可以利用隱藏索引快速測試刪除索引後對 SQL 查詢效能的影響,而無需進行索引刪除、重建操作,如果需要該索引,再設定可見就好了,這在大表測試中無疑非常有用,因為對於大表索引的刪除和重新新增很耗效能,甚至影響表的正常工作。 ## 隱藏索引設定 如果一個索引被設定成隱藏了,但實際上又需要被優化器所使用,有幾種表索引情況缺失對查詢造成的影響: 1)SQL 查詢語句中包含了索引提示指向不可見索引會發生錯誤; 2)效能模式資料中顯示了受影響 SQL 查詢語句的負載增高; 3)SQL 查詢語句進行 EXPLIAN 時出現了不同的執行計劃; 4)SQL 查詢語句出現在了慢查詢日誌中(之前沒有出現); 系統變數 optimizer_switch 的 **use_invisible_indexes** 標誌的值,控制了優化器執行計劃構建時是否使用隱藏索引。 如果 use_invisible_indexes 值設定為 **off** 關閉狀態(預設值),優化器預設會忽略隱藏索引,即和加入該引數之前的效果一樣。 如果 use_invisible_indexes 值設定為 **on** 開啟狀態,隱藏索引仍然保持不可見,但優化器會把隱藏索引加入到執行計劃的構建中。 如果想要在某條單個 SQL 查詢語句上啟用隱藏索引,可以使用 SET_VAR 優化器提示來臨時更新 optimizer_switch 的值,如下所示: ``` mysql> EXPLAIN SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ > age, weight FROM javastack WHERE weight >= 150\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: javastack partitions: NULL type: range possible_keys: weight_idx key: weight_idx key_len: 5 ref: NULL rows: 2 filtered: 100.00 Extra: Using index condition mysql> EXPLAIN SELECT age, weight FROM javastack WHERE weight >= 150\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: javastack partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 5 filtered: 33.33 Extra: Using where ``` 索引的可見性不會影響索引的自身維護,例如,不管索引是可見還是不可見,每次表資料行的更改索引都會更新,並且唯一索引也可防止插入重複資料。 沒有顯式主鍵的表如果在 NOT NULL 列上有任何一個唯一索引,則仍可能成為有效的隱式主鍵。在這種情況下,第一個這樣的索引會對錶資料行施加與顯式主鍵相同的約束,並且該索引不能設定為不可見。 如以下表的定義: ``` CREATE TABLE javastack ( age INT NOT NULL, weight INT NOT NULL, UNIQUE weight_idx (weight) ) ENGINE = InnoDB; ``` 該表定義不包含任何顯式主鍵,但是 weight 列為 NOT NULL,在該列上建立的唯一索引在資料行上與主鍵具有相同的約束,並且不能使其不可見: ``` mysql> ALTER TABLE javastack ALTER INDEX weight_idx INVISIBLE; ERROR 3522 (HY000): A primary key index cannot be invisible. ``` 假設現在我們將一個顯式主鍵新增到表中: ```sql ALTER TABLE javastack ADD PRIMARY KEY (age); ``` 顯式主鍵不能設定為不可見,此時,weight 列上的唯一索引不再充當隱式主鍵,因此可以使其設定不可見。 ``` mysql> ALTER TABLE javastack ALTER INDEX weight_idx INVISIBLE; Query OK, 0 rows affected (0.03 sec) ``` ## 總結 本文介紹了 MySQL 8.0 中的新特性:隱藏(不可見)索引,這個索引並不是新加的索引型別,而是可以控制索引是否加入到執行計劃的構建之中。 在實際生產中也可以利用隱藏索引進行 SQL 語句的效能測試,或者對索引進行邏輯刪除,以及索引的灰度釋出測試等,用處還是蠻大的。 本次的分享就到這裡了,希望對大家有用。覺得不錯,在看、轉發分享一下哦~ 最後,MySQL 系列教程還會繼續更新,關注Java技術棧公眾號第一時間推送,還可以在公眾號選單中獲取歷史 MySQL 教程,都是乾貨。 參考文件: > https://dev.mysql.com/doc/refman/8.0/en/invisible-indexes.html 話說你們用的 MySQL 哪個版本呢?來投票一下! 另外,關注公眾號Java技術棧,在後臺回覆:面試,可以獲取我整理的 MySQL 系列面試題和答案,非常齊全。 > 版權申明:本文系公眾號 "Java技術棧" 原創,原創實屬不易,轉載、引用本文內容請註明出處,禁止抄襲、洗稿,請自重,尊重他人勞動成果和智慧財產權。 **近期熱文推薦:** 1.[Java 15 正式釋出, 14 個新特性,重新整理你的認知!!](http://www.javastack.cn/article/2020/java15-released/) 2.[終於靠開源專案弄到 IntelliJ IDEA 啟用碼了,真香!](http://www.javastack.cn/article/2020/intellij-idea-by-open-source-project/) 3.[我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看。。](http://www.javastack.cn/article/2020/java-8-optional-map-do-you-know/) 4.[吊打 Tomcat ,Undertow 效能很炸!!](http://www.javastack.cn/article/2020/undertow-introduce-with-spring-boot/) 5.[《Java開發手冊(嵩山版)》最新發布,速速下載!](http://www.javastack.cn/article/2020/alibaba-release-java-develop-rules-songshan/) 覺得不錯,別忘了隨手點贊+轉發哦!