MySQL Join算法與調優白皮書(三)

Batched Key Access Join
Index Nested-Loop Join雖好,可是經過輔助索引進行連接後須要回表,這裏須要大量的隨機I/O操做。若能優化隨機I/O,那麼就能極大的提高Join的性能。爲此,My SQL 5.6推出了Batched Key Access Join,該 算法經過常見的空間換時間,隨機I/O轉順序I/O,以此來極大的提高Join的性能。
 
MRR
在說明Batched Key Access Join前,首先介紹下MySQL 5.6的新特性mrr——multi range read。這個特性根據rowid順序地,批量地讀取記錄,從而提高數據庫的總體性能。看下面的SQL語句的執行計劃:
 
mysql> explain select * from orders  
-> where o_orderdate >= '1993-08-01' 
-> and o_orderdate < date_add(  '1993-08-01' ,interval '3' month)\G
*************************** 1. row  ***************************
            id: 1
   select_type: SIMPLE
         table: orders
    partitions: NULL
          type: range
possible_keys: i_o_orderdate
          key:  i_o_orderdate
       key_len: 4
           ref: NULL
          rows: 143210
      filtered: 100.00
         Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
 
上述的SQL語句須要根據輔助索引i_o_orderdate進行查詢,可是因爲要求獲得的是表中全部的列,所以須要回表進行讀取。而這裏就可能伴隨着大量的隨機I/O。這個過程以下圖所示:

而mrr的優化在於,並非每次經過輔助索引讀取到數據就回表去取記錄,而是將其rowid給緩存起來,而後對rowid進行排序後,再去訪問記錄,這樣就能將隨機I/O轉化爲順序I/O,從而大幅地提高性能。這個過程以下所示:

從上圖能夠發現mrr經過一個額外的內存來對rowid進行排序,而後再順序地,批量地訪問表。這個進行rowid排序的內存大小由參數read_rnd_buffer_size控制,默認256K。
 
要開啓mrr還有一個比較重的參數是在變量optimizer_switch中的mrr和mrr_cost_based選項。mrr選項默認爲on,mrr_cost_based選項默認爲off。mrr_cost_based選項表示經過基於成本的算法來肯定是否須要開啓mrr特性。然而,在MySQL當前版本中,基於成本的算法過於保守,致使大部分狀況下優化器都不會選擇mrr特性。爲了確保優化器使用mrr特性,請執行下面的SQL語句:
 
mysql>set optimizer_switch='mrr=on,mrr_cost_based=off';  
 
一樣執行前面的SQL語句,能夠發現這時優化的執行計劃爲:
 
mysql> explain select * from orders where 
-> o_orderdate >= '1993-08-01' 
-> and o_orderdate < date_add('1993-08-01' ,interval '3' month)\G
*************************** 1. row***************************
          id: 1
 select_type: SIMPLE
       table: orders
  partitions: NULL
        type: range
possible_keys: i_o_orderdate
         key: i_o_orderdate
     key_len: 4
         ref: NULL
        rows: 143210
    filtered: 100.00
       Extra: Using index condition; Using MRR
1row in set, 1 warning (0.00 sec)
 
最後來對比一下關閉和開啓mrr特性後上述SQL的執行時間:

在講述完mrr特性後,再來看BKA Join就很是清晰明瞭了。經過mrr特性優化Join的回表操做,從而提高Join的性能。這時BKA Join的整個過程以下所示:

然而,這麼好的特性,倒是在MySQL中默認關閉的!!!這多是致使用戶認爲MySQL Join性能比較差的一個緣由。若要使用BKA Join,務必執行下列的SQL語句:
 
mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
Query OK, 0 rows affected (0.00 sec)
 
若開啓了BKA Join,則經過EXPLAIN命令,能夠發現優化器的執行結果選項會有Using join buffer (Batched Key Access)的提示,如:
 
mysql> explain SELECT
-> COUNT(*)
-> FROM
-> part,
-> lineitem
-> WHERE
-> l_partkey, = p_partkey
-> AND p_retailprice > 2050 AND p_size < 100
-> AND l_discount > 0.04\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: part
partitions: NULL
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 196810
filtered: 11.11
Extra: Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: lineitem
partitions: NULL
type: ref
possible_keys: i_l_suppkey_partkey,i_l_partkey
key: i_l_suppkey_partkey
key_len: 5
ref: dbt3_s1.part.p_partkey
rows: 28
filtered: 33.33
Extra: Using where; Using join buffer (Batched Key Access)
2 rows in set, 1 warning (0.00 sec)
 
最後來看下執行速度,能夠發現BKA的提高很是明顯:

未完待續
相關文章
相關標籤/搜索