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