mysql explain預估剖析

zhanlijun發表於2013-09-22

http://www.cnblogs.com/LBSer/p/3333881.html

引子:

  使用MySQL建立了一張表country,總共有才3121行記錄。

  但是使用explain select count(*) from country;的時候,發現行數rows達到6897,讓我大吃一驚。

mysql> explain select count(*) from country;

+----+-------------+---------+------+---------------+------+---------+------+------+-------+

| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |

+----+-------------+---------+------+---------------+------+---------+------+------+-------+

|  1 | SIMPLE      | country | ALL  | NULL          | NULL | NULL    | NULL | 6897 | NULL  |

+----+-------------+---------+------+---------------+------+---------+------+------+-------+

 

問題:為什麼explain的結果和真實的結果執行不一致,並且產生這麼大的誤差?

  針對這個問題,上網查了些資料,特此發博文總結下,當然自己也是剛剛使用mysql,有很多不瞭解的地方,希望多多指正。

一、explain是什麼?

  通過explain可以檢視MySQL的執行計劃,從而知道MySQL是如何處理我們的SQL語句。具體來說通過explain我們能得到一系列的關鍵資訊,比如哪些索引被實際使用,查詢了多少行等等。

  explain使用Rows來告知我們資料庫即將要閱讀的行數,但是實際將要閱讀的行數和explain所記載的將要閱讀的行數可能會有差異,這是因為explain並沒有真的去執行sql語句從而得出行數,而是進行了某種預估。

二、explain怎麼預估行數

  找了半天得知真相的我眼淚掉下來:http://lists.mysql.com/commits/115810

1)mysql-5.5之前

  首先找到查詢第一個記錄所在的page(記為PLeft),統計PLeft裡的記錄數(記為Records_PLeft),之後找到最後一個記錄所在的page(記為PRight),統計PRight的記錄數(Records_PRight),之後將Records_PLeftRecords_PRight取平均,最後乘以總共的page數目(記為Page_Num)。公式如下:

Rows = ((Records_PLeft + Records_PRight)/2)*Page_Num

  統計上講這個預估方法是很有偏的。比如總共4個page:page1(999 records), page2(1 record), page3(1 record), page4(1 record),這樣預估出來的Rows=((999+1)/2)*4 = 2000,然而實際上才總共才有1002個記錄。

2)mysql-5.5之後

  上述預估偏差大的關鍵在於有偏,而有偏的關鍵在於取樣的page數太少了,事實上只取樣了邊界2個,新演算法的思路很簡單,增加取樣數目,比如取樣10個page,這樣可以在一定程度上降低偏差。

  具體來說,mysql除了邊界2個外,還沿著左側page往右連續查詢8個page,如果總的page數目小於等於10個,那麼預估的Rows和真實的Rows一致。

Rows = ((Records_PLeft +  Records_P1 + Records_P2 + ... + Records_P8 + Records_PRight)/10)*Page_Num

   上述方法只是在一定程度上緩解了有偏的問題,但是不準確還是存在的,事實上樓主的mysql版本是5.6版本,可見還是沒有解決的很好

 三、思考

  為什麼是從左往右連續選8個page,而不是在首尾之間隨機選擇8個page,既然要緩解取樣有偏的問題,那麼隨機選應該更好。猜想可能有兩個原因:1)隨機選擇每次explain得到的Rows不一樣,不方便應用;2)隨機選會造成I/O開銷,尤其是資料量大的時候,畢竟explain是希望能快速得到預估結果。

  我覺得應該還有更好的演算法,能實現explain效率與精度的tradeoff,希望大家能給出建議。

相關文章