2013-07-19 116 views
8

我想弄清楚爲什麼我的一個查詢速度慢,我如何解決它,但我對我的結果有點困惑。爲什麼MySQL在查詢中使用LIMIT時速度很慢?

我有一個orders表周圍80列和775179行和我做以下請求:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200

這在4.5S

返回38行當除去ORDER BY我很好的改進:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL LIMIT 200

分38排在0.30s

但沒有接觸ORDER BY我得到一個更好的結果取出LIMIT時:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC

38排在0.10s(??)

爲什麼我的LIMIT如此飢餓?

的進一步深入

送我的答案之前注意到,我有一個指數creation_date(這是一個datetime)我刪除它和第一個查詢現在0.10s運行後,我嘗試了一些東西。這是爲什麼 ?

編輯

好猜,我對那裏的人列部分索引。

mysql> explain SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200; 
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+ 
| id | select_type | table | type | possible_keys   | key  | key_len | ref | rows | Extra  | 
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+ 
| 1 | SIMPLE  | orders | index | id_state_idx,id_mp_idx | creation_date | 5  | NULL | 1719 | Using where | 
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+ 

1行集(0.00秒)

mysql> explain SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC; 
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+ 
| id | select_type | table | type | possible_keys   | key  | key_len | ref | rows | Extra            | 
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+ 
| 1 | SIMPLE  | orders | range | id_state_idx,id_mp_idx | id_mp_idx | 3  | NULL | 87502 | Using index condition; Using where; Using filesort | 
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+ 
+5

因爲在第一次查詢後,結果被(部分)緩存爲以下查詢... – Mr47

+1

事實並非如此,重新運行同樣的查詢給了我一致的結果 –

+0

也許你的服務器很慢.... – pattyd

回答

6

指標不一定提高性能。爲了更好地理解正在發生的事情,如果您爲不同的查詢包含explain,將會有所幫助。

我最好猜測的是你有一個id_state甚至id_state, id_mp索引,可以用來滿足where條款。如果是這樣,沒有order by的第一個查詢將使用此索引。它應該很快。即使沒有索引,也需要依次掃描orders表中的頁面,該表格仍然非常快。

然後,當您在creation_date上添加索引時,MySQL決定使用該索引代替order by。這需要讀取索引中的每一行,然後獲取相應的數據頁面以檢查條件並返回列(如果匹配)。這種閱讀效率非常低,因爲它不在「頁面」順序中,而是由索引指定。隨機讀取可能效率很低。

更糟的是,即使您有limit,您仍需要閱讀整個表,因爲需要整個結果集。儘管您已對38條記錄進行了排序,但您已經創建了大量低效的查詢。

順便說一句,如果orders表不適合可用內存,這種情況會變得更糟糕。然後你有一個叫做「thrashing」的條件,每個新記錄往往會產生一個新的I/O讀取。所以,如果一個頁面上有100條記錄,那麼該頁面可能必須被讀取100次。

通過在orders(id_state, id_mp, creation_date)上設置索引,可以使所有這些查詢的運行速度更快。 where子句將使用前兩列,而order by將使用最後一列。

+0

很好的答案,但是在775179個記錄表上,我會說索引是需要的嗎? –

+1

@KayNelson。 。 。是。這就是爲什麼我在最後一段提出更好的指數。我想要小心一點,因爲如果沒有解釋,答案都是猜測。 –

+0

是的,這是非常真實的! –

0

同樣的問題發生在我的項目, 我做了一些測試,發現了該限制是因爲行查找緩慢

參見: MySQL ORDER BY/LIMIT performance: late row lookups

所以,解決的辦法是:

(A)當使用LIMIT時,請選擇不是所有列,但只選擇PK列

(B)選擇您需要的所有列,然後加入結果集(A)

SQL應該喜歡:

SELECT 
    * 
FROM 
    orders O1 <=== this is what you want 
JOIN 
    (
     SELECT 
      ID       <== fetch the PK column only, this should be fast 
     FROM 
      orders 
     WHERE 
      [your query condition]  <== filter record by condition 
     ORDER BY 
      [your order by condition] <== control the record order 
     LIMIT 2000, 50     <== filter record by paging condition 
    ) as O2 
ON 
    O1.ID = O2.ID 
ORDER BY 
    [your order by condition]   <== control the record order 
在我的DB

老SQL其中選擇使用 「LIMIT 21560,20」 中的所有列,費用約4.484s。

新的sql成本只有0.063s。新的速度大約快71倍

相關問題