MySQL8.0之跳躍範圍掃描

簡介

跳躍範圍掃描是MySQL在8.0.13版本新增長的用於提升性能的新特性,跳躍範圍掃描可使之前部分沒法使用到聯合索引的SQL利用聯合索引進行查詢,而且能夠更高效的利用聯合索引,這對於使用MySQL聯合索引進行查詢的應用意義重大。mysql

環境信息

  • MySQL版本:8.0.15
  • 操做系統版本:redhat-7.4

跳躍範圍掃描

經過一個示例來解釋跳躍範圍掃描:sql

CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2));
INSERT INTO t1 VALUES(1,1), (1,2), (1,3), (1,4), (1,5),(2,1), (2,2), (2,3), (2,4), (2,5);
INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
ANALYZE TABLE t1;
EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 53
     filtered: 100.00
        Extra: Using where; Using index for skip scan
1 row in set, 1 warning (0.00 sec)


mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.15 |
+-----------+
1 row in set (0.00 sec)
複製代碼

在這個示例中,SELECT f1,f2 FROM t1 WHERE f2>40在8.0.13版本以前是經過索引全掃描的方式來獲取最終的結果集,由於SELECT查詢的字段所有都是索引的組成部分。MySQL經過索引全掃描獲取全部的行記錄,而後經過f2 > 40這個條件過濾,最終篩選出結果集返回給客戶端。bash

衆所周知,索引範圍掃描的效率確定是要高於索引全掃描的,在這個示例中,雖然查詢條件是f2 > 40,屬於範圍查詢,可是WHERE條件中不包含f1字段的的條件,因此沒法使用索引範圍掃描的方式過濾數據。在MySQL-8.0.13版本增長的跳躍範圍掃描特性,就是針對相似的場景的優化,跳躍範圍掃描在這個示例中實際是針對每個f1字段的值,進行了範圍掃描,即進行了屢次範圍掃描。 針對這個示例,具體的跳躍範圍掃描過程以下:性能

  1. 獲取聯合索引中第一個字段f1的第一個值:f1 = 1
  2. 將獲取到的值和WHERE條件中的f2的條件組合:f1 = 1 AND f2 > 40
  3. 執行這個範圍掃描查詢
  4. 獲取聯合索引中第一個字段f1的第二個值:f1 = 2
  5. 將獲取到的值和WHERE條件中的f2的條件組合:f1 = 2 AND f2 > 40
  6. 執行這個範圍掃描查詢
  7. 將兩次範圍掃描查詢的結果合併返回給客戶端

跳躍範圍掃描實際就是將一些全掃描的場景拆分紅多個範圍掃描,利用範圍掃描的效率高於全掃描的效率,最終實現提升SQL效率。 在這個示例中,比較有跳躍範圍掃描特性的SQL執行計劃以及沒有跳躍範圍掃描特性的SQL執行計劃:優化

# 有跳躍範圍掃描特性

mysql> EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 53
     filtered: 100.00
        Extra: Using where; Using index for skip scan
1 row in set, 1 warning (0.00 sec)

# 沒有跳躍範圍掃描特性
mysql> EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40\G 
 *************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 160
     filtered: 33.33
        Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
複製代碼

經過執行計劃能夠看到,有跳躍範圍掃描特性的查詢掃描的行數更少且過濾性更高。ui

使用限制以及場景

下面來講說跳躍範圍掃描使用一些限制以及場景:spa

  • 表上至少存在一個聯合索引([A_1,A_2...A_k],B_1,B_2...B_m,C,[,D_1,...,D_n]),其中A部分以及D部分能夠爲空,可是B和C部分不能爲空。A_1,A_2..等表明字段值
  • 只針對單表查詢
  • 查詢中不包含GROUP BY或者DISTINCT
  • SELECT查詢的字段所有被包含在索引組成部分,即符合覆蓋索引規範
  • 前綴A_1,A_2...A_k部分必須是能夠被相等的常量
  • 字段C上必須是一個範圍條件,大於或大於等於,小於或小於等於
  • 容許在D字段上有過濾條件,可是必須和C上的範圍條件一塊兒使用

跳躍範圍掃描默認是開啓的,有兩種方式能夠關閉跳躍範圍掃描特性:操作系統

  • 經過修改optimizer_switcher變量值,默認MySQL是將optimizer_switcher中的skip_scan設置爲on的,能夠經過將skip_scan設置爲off關閉跳躍範圍掃描
  • 經過Hint的方式關閉跳躍範圍掃描特性:SELECT/*+ NO_SKIP_SCAN(t1 PRIMARY) */ f1, f2 FROM t1 WHERE f2 > 40;

對於使用了跳躍範圍掃描特性的SQL,使用EXPLAIN查看其執行計劃,能夠看到:code

  • 在執行計劃輸出的Extra一欄中有:Using index for skip scan
  • 在執行計劃輸出的possible_keys一欄中會顯示可使用到的索引

總結

跳躍範圍掃描是對使用MySQL聯合索引查詢的SQL意義重大,能在使SQL查詢效率更高,可是並非使用到跳躍範圍掃描就能表明SQL執行效率更高。在MySQL一些開發規範中,通常要求創建聯合索引時將重複值少的字段放在聯合索引前面,將重複值多的字段放在聯合索引後面,方便SQL在使用聯合索引時經過前面的字段快速過濾結果。可是在跳躍範圍掃描特性中,是遍歷前面字段的值,與後續字段的範圍查詢條件組合,進行範圍掃描查詢,那對於重複值少的字段會被拆分紅多個範圍掃描查詢,在實際使用過程當中並不必定會比索引全掃描效率更高。索引

因此我的以爲跳躍範圍掃描適用於聯合索引中前導列distinct值較少,後續字段選擇過濾性又比較好的場景,能更好的發揮跳躍範圍掃描的做用。

相關文章
相關標籤/搜索