MySQL中大於小於,IN,OR,BETWEEN效能比較
在MySQL中經常會有朋友問關於大於小於,IN,OR,BETWEEN,哪個效能更好?
我想有很多朋友會用它們但確實不知道大於小於,IN,OR,BETWEEN效能哪個更好吧,下面總結一下關於大於小於,IN,OR,BETWEEN效能。
這裡的查詢條件有四種:>=和<=;between;or;in
這裡id列是索引列,如果不是的話,三個查詢都是全表掃描,效能差距應該不大。
1 準備環境
mysql> show create table tinG
mysql> show create procedure init_tinG mysql> call init_tin(5000)G |
2 檢視執行計劃
為了簡單起見,選擇[100,104]這個區間。
查詢語句為:
SELECT * FROM tin where c1 >= 100 and c1 <= 104; |
其中,在MySQL中 c1 >= 100 and c1 <= 104
首先檢視explain輸出,會發現三個語句的explain輸出是一樣的:
*************************** 1. row *************************** |
MySQL5.6在information_schema中增加了optimizer_trace表,用於跟蹤語句生成的執行計劃的具體步驟,包含各種關鍵的優化步驟。
分別看下三種不同語句的執行代價:
1. SELECT * FROM tin where c1 >= 100 and c1 <= 104;
SELECT * FROM tin where c1 >=100 and c1 <=104; “chosen_range_access_summary”: { “range_access_plan”: { “type”: “range_scan”, “index”: “PRIMARY”, “rows”: 5, “ranges”: [ “100 <= c1 <= 104″ ] }, “rows_for_plan”: 5, “cost_for_plan”: 2.0188, “chosen”: true } |
2. SELECT * FROM tin where c1 in (100, 101, 102, 103, 104);
SELECT * FROM tin where c1 in (100, 101, 102, 103, 104); “chosen_range_access_summary”: { “range_access_plan”: { “type”: “range_scan”, “index”: “PRIMARY”, “rows”: 5, “ranges”: [ “100 <= c1 <= 100″, “101 <= c1 <= 101″, “102 <= c1 <= 102″, “103 <= c1 <= 103″, “104 <= c1 <= 104″ ] }, “rows_for_plan”: 5, “cost_for_plan”: 6.0188, “chosen”: true } |
3. SELECT * FROM tin where c1 = 100 or c1 = 101 or c1 = 102 or c1 = 103 or c1 = 104;
SELECT * FROM tin where c1 = 100 or c1 = 101 or c1 = 102 or c1 = 103 or c1 =104; “chosen_range_access_summary”: { “range_access_plan”: { “type”: “range_scan”, “index”: “PRIMARY”, “rows”: 5, “ranges”: [ “100 <= c1 <= 100″, “101 <= c1 <= 101″, “102 <= c1 <= 102″, “103 <= c1 <= 103″, “104 <= c1 <= 104″ ] }, “rows_for_plan”: 5, “cost_for_plan”: 6.0188, “chosen”: true } |
從上面可以看出執行代價最小的語句為SELECT * FROM tin WHERE c1 >= 100 and c1 <=104,代價為2.0118,其他兩個計劃的代價 為6.0118。
3 計劃分析
看了上面的代價結果,是不是就理所當然的任務第一個語句的代價真的是最小呢?
這就需要知道MySQL代價計算的方法, 一個計劃的代價體現在硬體上就是I/O + CPU,I/O就是將所需的物理頁載入記憶體的時間,CPU則是資料計算所消耗的時間, 有些語句是I/O密集的,有些語句是CPU運算密集的。
為什麼MySQL計算出來的代價會差別這麼大呢?
MySQL在計算上面三個語句的代價時,I/O代價的計算是由range的個數n_ranges和最終的結果集的行數total_rows得出來的,
語句1的n_ranges=1
語句2和語句3的n_ranges=5
totol_rows都為5
故語句1的在I/O上的代價明顯小於語句2和語句3(具體的函式參見ha_innobase::read_time)。
至於CPU的代價,由於返回的行數一致,故CPU的代價一致,CPU的代價主要體現在獲取資料後,進行WHERE 條件的匹配操作。
這只是MySQL的對於上面三個語句的代價模型,而實際上,上面三個語句所進行的I/O操作其實是一致的,因為資料範圍是一樣的。所以,僅憑 MySQL給出的代價結果還是不能立刻判斷出語句1就肯定好。
既然I/O操作的代價可以考慮是一致的,那麼只能來看三條語句執行時的區別了。
語句2和語句3的range個數都為5個,而且range的範圍都是一致的,這其實是MySQL的優化結果,IN和OR都被優化成了相同的結果。只有語句1只有1個range。MySQL執行時是遍歷每個range,而每個range遍歷時其實是兩種操作,read_first和read_next,read_first是根據每個range的start key定位到相應的位置,read_next則是根據上次BTREE讀到的位置, 繼續往後讀,read_next是以end key為結束。
對於語句1,只有一個range,故需要1次read_first和5次read_next(最後一次read_next不符合end_key,返回結束)
對於語句2和語句3, 有5個range,每個range需要1此read_first和一次read_next,總共需要5此read_first和5次read_next。
從資料獲取的次數來看,語句2和語句3基本是語句1的呼叫次數的兩倍。
合法性的驗證
除了獲取資料呼叫次數的區別外,在獲取資料之後,還需要進行資料合法性的驗證,即匹配WHERE條件。
對於語句1的WHERE條件十分簡單,匹配上下界限即可,即對於每返回的一行資料需要兩次驗證,時間複雜度為常量O(2)。
對於語句2和語句3,則需要對IN或OR中的每個條件進行驗證,知道找到某一匹配項為止,時間複雜度為O(n)。 但是MySQL對於IN做了相應的優化,即將IN中的常量全部儲存在一個數組裡面,而且這個陣列是排好序的,故匹配的時候是二分查詢, 時間複雜度為O(lgn)。
在忽略I/O的情況下,僅僅從CPU的耗時來看,語句1應該是最少的,其次是IN,最差的就是OR
先就分析到這吧,具體的執行時間的資料這裡沒測試,感興趣的可以進一步測試下!
上面是想通過測試瞭解MySQL內部的優化流程,可能單獨測試的時候語句執行效率差別不是很大。
參考自:http://blog.csdn.net/u011781769/article/details/48471013