MySQL非惟一索引值分佈不均勻與優化器參數eq_range_index_dive_limit

MySQL5.6引入了一個新的系統變量eq_range_index_dive_limit。這可能會顯着影響查詢執行計劃。這裏我舉一個典型的例子。
 
有一個表「t」。主鍵由從「id1」開始的多個列組成。表t中有1.67M行,id1的基數是46K(這些數字能夠經過SHOW TABLE STATUS / SHOW INDEX收集)。所以,每一個id1平均有36行(1.67M / 46K = 36),但實際的id1分佈是不均勻的。有接近1M行,其中id1在1和10之間。
 
mysql> explain select count(*)from t force index(PRIMARY)where id1 in(1,2,3,4,5,6,7,8,9)\ G
*************************** 1.行******************** *******
           id:1
  select_type:SIMPLE
        table:t
         type:range
possible_keys:PRIMARY
          key:PRIMARY
      key_len:8
          ref:NULL
         rows:912388
       extra:using where;using index 
1 row(0.00 sec)
 
MySQL估計912K行匹配,其中id1 IN(1..9)。這接近實際數字。 MySQL5.6引入了持久化優化器統計,使統計信息更準確。
 
mysql>explain select count(*)from t force index(PRIMARY)where id1 in(1,2,3,4,5,6,7,8,9,10)\ G
*************************** 1.行******************** *******
           id:1
  select_type:SIMPLE
        table:t
         type:range
possible_keys:PRIMARY
          key:PRIMARY
      key_len:8
          ref:NULL
         rows:360
        extra:using where;using index 
1 row(0.00 sec)
 
當添加一個IN條件(id1 IN(1..10))時,忽然估計的行數降低到360!這比實際匹配的行數小得多。估計的行數愈來愈少(或更大)常常使MySQL選擇不正確的查詢執行計劃,因此這是真的很嚴重。
 
估計的行數變化很大的緣由是一個新的系統變量eq_range_index_dive_limit。如在線手冊所述,「若是eq_range_index_dive_limit大於0,若是有eq_range_index_dive_limit或更多相等範圍」,優化器將使用現有索引統計信息而不是索引潛水。默認eq_range_index_dive_limit爲10.所以,當設置10個或更多IN條件時,MySQL會跳過索引dive,並從統計信息中估計行數。在這個例子中,MySQL估計360行(1.67M(表t的估計總行數)/ 46K(基數id1)* 10(IN條件)== 360)。
 
經過增長eq_range_index_dive_limit足夠大,MySQL不會錯誤地估計行。
 
mysql> set session eq_range_index_dive_limit = 1000;
query OK,0 row affected(0.00秒)
 
mysql>explain select count(*)from t force index(PRIMARY)where id1 in(1,2,3,4,5,6,7,8,9,10)\ G
*************************** 1.行******************** *******
           id:1
  select_type:SIMPLE
        table:t
         type:range
possible_keys:PRIMARY
          key:PRIMARY
      key_len:8
          ref:NULL
         rows:937684
        extra:using where;using index 
1 row(0.00 sec)
 
設置10個或更多的IN條件是很常見的,不均勻分佈的索引也很常見。 eq_range_index_dive_limit有助於減小查詢執行計劃的index dive成本,但咱們認爲10過小了。MySQL 5.7目前默認設置爲200

第一次發表在php

http://www.yougemysqldba.com/discuz/viewthread.php?tid=500&extra=page%3D1mysql

相關文章
相關標籤/搜索