2013-04-14 47 views
2

我在我的web-app中使用下面的查詢。它查詢的是結果表格,其中包含網絡商店在給定時間的價格。它有大約100萬條記錄。索引是一個shopID,StartTime,pID和WebsiteID。簡單,索引良好,MySQL查詢大約需要一秒鐘

查詢:

SELECT shopID, tresults.StartTime, tresults.Price 
FROM tresults 
WHERE tresults.pID = 7 
    AND WebsiteID = 1 AND StartTime BETWEEN "2013-4-10" AND "2013-4-11" 
    AND tresults.shopID IN (44, 68, 23, 16, 144, 8, 9, 5) 
GROUP BY tresults.StartTime, tresults.Price 
ORDER BY tresults.StartTime, tresults.Price 

的解釋結果:

1, SIMPLE, tresults, index_merge, PRIMARY,idxPID,idxWebsite,idxStartTimeASC,idxStartTimeDESC,fk_shopID, idxPID,idxWebsite, 4,4, , 1062, Using intersect(idxPID,idxWebsite); Using where; Using temporary; Using filesort 

看起來好像沒什麼問題,但還是查詢需要大約一秒鐘來完成。這在快速網站中是不可接受的。

我該如何加快速度?

注:速度看起來是依賴於shopID的

感謝的數量!

+2

你沒注意到tresults.pID = 7時提到兩次?從這些百萬行中選擇了多少行?你爲什麼分組?排序應該是足夠的... – rene

+0

pID = 7不應該在那裏兩次(雖然在性能上沒有差別)。它從這些百萬人中選擇了大約500行。分組在那裏,因爲我認爲這是我從結果中創建的圖表所必需的。刪除它不會使性能不同,不幸的是。 – kay10

回答

1

創建以下指標:

CREATE INDEX idxTresults_pwsp ON tresults (pId, WebsiteID, StartTime, Price); 

這是縮小搜索範圍的最佳途徑,也可防止「使用臨時」和「使用文件排序」。

mysql> EXPLAIN 
SELECT shopID, tresults.StartTime, tresults.Price 
FROM tresults 
WHERE tresults.pID = 7 
    AND WebsiteID = 1 AND StartTime BETWEEN '2013-4-10' AND '2013-4-11' 
    AND tresults.shopID IN (44, 68, 23, 16, 144, 8, 9, 5) 
GROUP BY tresults.StartTime, tresults.Price 
ORDER BY tresults.StartTime, tresults.Price 
\G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: tresults 
     type: ref 
possible_keys: idxpid,idxStarttime,fkShop_id,idxTresults_pwsp 
      key: idxTresults_pwsp 
     key_len: 9 
      ref: const,const 
     rows: 1 
     Extra: Using where 

這個效果更好的原因是指數幫助的第一個兩個欄只選擇行權集爲特定的PID和WebsiteID。由於您選擇了一個特定的pID和WebsiteID,因此這個新索引中的所選條目已確保按照StartTime和Price的最佳順序排序,因此查詢不需要創建臨時表。它只是按照它們存儲在索引中的順序訪問條目。

PS:MySQL不支持「升序」與「降序」索引。它接受關鍵字,但它與它們沒有任何不同。所以你不需要給定列上的兩種類型的索引。

PPS:不要使用雙引號的字符串或日期文字。使用單引號,以符合ANSI SQL。如果您使用其他品牌的RDBMS,那麼您會更好地適應這種習慣,因爲大多數其他品牌都會根據標準使用報價。 MySQL允許以非標準方式使用雙引號。

+1

哇......這就像一個魅力。感謝:1,加快我的web應用程序的頁面加載約半秒,2。讓我明白擺脫我的雙引號,壞習慣的方式多山坳索引工作,3。我對上面的麥地那抱歉。但這必須是唯一正確的答案。 – kay10

3

您的查詢不像您想象的那麼好。它使用「使用臨時」和「使用filesort」。這意味着它已被保存在文件系統中,被解析器操作並使查詢速度變慢。

要嘗試改進它,您可以嘗試使子句中的字段與您在表中獲得的索引相匹配。甚至,按照以下順序創建新索引:pID,websiteID,startTime,如果您的查詢將始終使用這些元素運行。

我也不明白你爲什麼在查詢中有兩次tresults.pID字段。

[編輯]

嘿夥計,你得到的臨時表,因爲你正在使用聚合函數來處理結果集,例如GROUP BY,ORDER BY,HAVING等。只要臨時表保存在內存中就行,這是訪問數據的更快方式。問題是這些表達到分析器必須將它們帶到文件系統的大小。

您可以嘗試找到最佳平衡更改tmp_table_size和max_heap_table_size的值。此外,儘量避免內存存儲不支持它們時使用博客/文本列。

更多信息可以在官方文檔中找到。

+0

我創建了你建議的索引,但它仍然使用臨時和filesort。還有其他建議嗎? – kay10

+1

嗯......我剛剛在tresults.pID和tresults.WebsiteID上創建了一個索引。這做了很大的改進。查詢時間從1秒變爲0.15秒。儘管解釋結果仍然表明mysql使用臨時文件和文件。我現在很開心! ;)感謝您指點我正確的方向! – kay10

+0

感謝梅迪納的編輯。但比爾卡爾文的解決方案比你的解決方案還要快 – kay10