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

2021-02-13 碼小辮

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.

假設現在我們將一個顯式主鍵添加到表中:

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 語句的性能測試,或者對索引進行邏輯刪除,以及索引的灰度發布測試等,用處還是蠻大的。


參考文檔:

https://dev.mysql.com/doc/refman/8.0/en/invisible-indexes.html

相關焦點

  • MySQL 8.0 可以操作 JSON 了,牛逼...
    作者:旺財不哭連結:https://www.jianshu.com/p/d4b012769a3b經過漫長的測試,即將整體遷移至Mysql8.0; Mysql8.0 對於Json操作新增/優化了很多相關Json的API操作。
  • MySQL索引與索引優化
    索引是對資料庫表中一個或多個列的值進行排序的結構,建立索引有助於快速獲取信息。你也可以這樣理解:索引就是加快檢索表中數據的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許用戶不必翻閱完整個書就能迅速地找到所需要的信息。在資料庫中,索引也允許資料庫程序迅速地找到表中的數據,而不必掃描整個資料庫。
  • MySQL 一千個不用 Null 的理由
    Mysql難以優化引用可空列查詢,它會使索引、索引統計和值更加複雜。可空列需要更多的存儲空間,還需要mysql內部進行特殊處理。可空列被索引後,每條記錄都需要一個額外的字節,還能導致MYisam 中固定大小的索引變成可變大小的索引。照此分析,還真不是以訛傳訛,這是有理論依據和出處的。3、給我一個不用 Null 的理由?
  • 乾貨 | MySQL8.0新增配置參數詳解
    參數在版本8.0.1中引入,是可以動態調整的global級參數,8.0.4之前默認值為0,8.0.11之後為2592000也就是30天。此參數在版本8.0.1中引入,是可以動態調整的global級參數,默認值為25000,可以設置為0-1000000之間的任意整數。8.0基於WriteSet進行並行複製時,WriteSet是一個hash數組,binlog_transaction_dependency_history_size值就是這個hash數組的最大值。
  • Christina問我:你都是如何設計索引的?
    今天就跟大家聊聊MySQL中的索引以及如何設計索引,使用索引才能提降低接口的RT,提高用戶體檢。MySQL中的索引MySQL中的InnoDB引擎使用B+Tree結構來存儲索引,可以儘量減少數據查詢時磁碟IO次數,同時樹的高度直接影響了查詢的性能,一般樹的高度維持在 3~4 層。
  • MySQL 資料庫的哈希表-愛可生
    MySQL 的默認索引結構是 B+ 樹,也可以指定索引結構為 HASH 或者 R 樹等其他結構來適應不同的檢索需求。這裡我們來介紹 MySQL 哈希索引。MySQL 哈希索引又基於哈希表(散列表)來實現,所以了解什麼是哈希表對 MySQL 哈希索引的理解至關重要。
  • MySQL 是怎麼死鎖的?
    ,但id=5的記錄已經被鎖住了,鎖的等待在id=8的這裡不信請看Session3:mysql> select * from t3 where id=5 for update;鎖等待中Session4:mysql> select * from t3 where id=10 for update;+----+--
  • Mysql為啥用B+樹來做索引?
    一、為什麼需要索引?大家都知道,我們讀取數據時要避免全表掃描,那如何避免全表掃描呢?目前科學家給出的目標就是索引。索引就好比一本字典的目錄一樣,有了目錄讀者就不需要翻找全書來找內容。同樣有了索引,資料庫就不用全表掃描了。在一張數據表中不管你建不建索引都會有一個默認索引。
  • MySQL授權管理與結構分層
    *wordpress.t1授權需求創建一個管理員用戶root,可以通過10網段,管理資料庫grant all on *.* to root@'10.0.0.%' identified by 'on wordpress.* to wordpress@'10.0.0.%' identified by '123'回收權限查找用戶權限show grants for wordpress@'10.0.0.
  • 青銅到王者,快速提升你 MySQL 資料庫的段位!
    從圖中我們可以看出:MySQL 體系結構分兩部分(mysql server 層 + mysql 存儲引擎層)通過一條 sql 語句進入資料庫的過程細分,又可以由8個小部分組成如下圖2、adaptive hash index(自適應哈希索引)作用:Innodb 存儲引擎會監控對表上索引的查找,如果觀察到建立哈希索引可以帶來速度上的提升,則建立哈希索引。讀寫速度上也有所提高。
  • Mysql如何給字符串添加索引(前綴索引)
    where email='zhangsan@qq.com'在index1中找到符合條件的記錄,獲取id=5然後使用id=1,在主鍵索引上獲取整行記錄在index1尋找下一條記錄,直到發現不滿足位置,循環結束在index2中找到符合條件的值,獲取到id=1然後在主鍵索引中找到id=1的數據,發現不符合在index2
  • MySQL優化:定位慢查詢的兩種方法以及使用explain分析SQL
    開啟慢查詢日誌(默認是關閉的):mysql> set global slow_query_log = on;Query OK, 0 rows affected (0.00 sec)設置慢查詢時間限制(查詢時間只要大於這個值都將記錄到慢查詢日誌中,單位:秒):mysql> set global long_query_time = 1;
  • 這六個 MySQL 死鎖案例,能讓你理解死鎖的原因!
    -+-+rows in set (0.04 sec)Session2:select * from t3 where id in (10,8,5) for update;鎖等待中……其實這個時候id=10這條記錄沒有被鎖住的,但id=5的記錄已經被鎖住了,鎖的等待在id=8的這裡不信請看Session3:mysql>
  • MySQL Client中一些被遺忘的功能
    進入vi/vim中編輯sql,編輯完成之後保存,回到mysql CLI中,輸入「;」後按enter鍵即可執行剛才編輯的sql語句。name |+-+--+| 1 | sylar chen |+-+--+1 row in set (0.01 sec)4、記錄操作日誌\T,tee差不多就是linux tee命令的功能,把執行的sql語句以及輸出結果保存到指定的文件中。
  • 「詳細」MySQL資料庫與JDBC編程
    (MySQL不支持)CREATE TABLE 表名( key INT, CHECK(key>10) );索引(一個資料庫對象)創建索引的唯一作用是加速對表的查詢,索引通過使用快速路徑訪問方法來快速定位數據,從而減少了磁碟的I/0。
  • Mysql資料庫部分
    面試中我們經常會被要求做一份筆試題,筆試題通過後會有技術大佬來面試我們。在筆試題最後一般都是有一道關於mysql語句的問題,讓手寫出增、刪、改、查語句,今天我們就學習一下mysql語句。語句8:將語句7中的WHERE條件放到ON後面。從語句7和語句8查詢的結果來看,顯然是不相同的,語句8顯示的結果是難以理解的。因此,推薦在寫連接查詢的時候,ON後面只跟連接條件,而對中間表限制的條件都寫到WHERE子句中。語句9:全外連接(FULL OUTER JOIN)。
  • MySQL Innodb 如何找出阻塞事務源頭 SQL
    +--+| connection_id() |+--+|               8 |+--+1 row in set (0.00 sec)  mysql> set session autocommit=0;Query OK, 0 rows affected (0.00 sec
  • 100條MySQL規範,從入門到精通,很實用!
    >1、所有表必須使用Innodb存儲引擎沒有特殊要求(即Innodb無法滿足的功能如:列存儲,存儲空間數據等)的情況下,所有表必須使用Innodb存儲引擎(mysql5.5之前默認使用Myisam,5.6以後默認的為Innodb)Innodb 支持事務,支持行級鎖,更好的恢復性,高並發下性能更好2、資料庫和表的字符集統一使用UTF8
  • MySQL 工作、底層原理,看這一篇就夠了!
    比如表緩存,記錄緩存,key緩存,權限緩存等8.Engine (存儲引擎)存儲引擎是MySql中具體的與文件打交道的子系統。也是Mysql最具有特色的一個地方。Mysql的存儲引擎是插件式的。(2)buffer與cache的區別從mysql原理圖可以看到,緩存那裡實際上有buffer和cache兩個,那它們之間的區別:簡單的說就是,buffer是寫緩存,cache是讀緩存。
  • 總結零散的 MySQL 基礎知識
    在日常開發中,一些不常用且又比較基礎的知識,過了一段時間之後,總是容易忘記或者變得有點模稜兩可。本篇主要記錄一些關於MySQL資料庫比較基礎的知識,以便日後快速查看。 SQL命令分可以分為四組:DDL、DML、DCL和TCL。