2012-01-26 25 views
3

我覺得下面的查詢速度太慢:理念,提高此查詢索引

(1679.1ms) 
SELECT `media_files` . * 
FROM `media_files` 
INNER JOIN `playlist_media_files` ON `media_files`.`id` = `playlist_media_files`.`media_file_id` 
WHERE `media_files`.`type` 
IN (
'AudioFile' 
) 
AND `playlist_media_files`.`playlist_id` =7 
ORDER BY media_files.artist ASC , media_files.release_year ASC , media_files.album ASC , media_files.disc_number ASC , media_files.position ASC 

說明:

+----+-------------+----------------------+--------+---------------------------------------------------------------------------------------+-------------------------------------------+---------+---------------------------------------------------------+------+---------------------------------+ 
| id | select_type | table    | type | possible_keys                   | key          | key_len | ref              | rows | Extra       | 
+----+-------------+----------------------+--------+---------------------------------------------------------------------------------------+-------------------------------------------+---------+---------------------------------------------------------+------+---------------------------------+ 
| 1 | SIMPLE  | playlist_media_files | ref | index_playlist_media_files_on_playlist_id,index_playlist_media_files_on_media_file_id | index_playlist_media_files_on_playlist_id | 4  | const             | 3782 | Using temporary; Using filesort | 
| 1 | SIMPLE  | media_files   | eq_ref | PRIMARY,index_media_files_on_type              | PRIMARY         | 4  | mydb.playlist_media_files.media_file_id     | 1 | Using where      | 
+----+-------------+----------------------+--------+---------------------------------------------------------------------------------------+-------------------------------------------+---------+---------------------------------------------------------+------+---------------------------------+ 

每列索引。 任何MySQL專家都可以通過查看解釋來了解如何改進它?

的多個ORDER BY被查殺性能。

編輯:從意見

更新刪除私人網址:看來我可以爲後期ORDER BY排序像做concat(..fields..) AS sort

+0

每張表中有多少行以及索引基數是多少? 'SHOW INDEXES FROM tablename' – piotrm

回答

1

對於這個查詢,你可能會從playlist_media_files爲表上(playlist_id,media_file_id)複合索引中獲益,這將讓MySQL使用僅此指數知道從media_files讀哪一行,而不必從playlist_media_files讀取實際數據看對於滿足playlist_id = 7條件的每一行(他們中的很多人),media_file_id的值如何?

你應該可以看到更多的using index用於解釋輸出的第一行。

Mysql的仍然要創建臨時表這麼多列排序,但在內存中的排序4K行也不是那麼昂貴。

所以基本上嘗試:

ALTER TABLE `playlist_media_files` 
    ADD INDEX `playlist_media_composite` (`playlist_id` , `media_file_id`) ; 

,並查看結果。

編輯:我試圖模仿我的測試數據庫同樣的問題,創建相同的表,並使用PHP隨機400K行,試圖獲得類似的指數基數填充。 沒有綜合指數相同的查詢有以下執行計劃:

1 SIMPLE playlist_media_files ref  playlist_id,media_file_id playlist_id  4 const          3925 Using temporary; Using filesort 
1 SIMPLE media_files    eq_ref PRIMARY      PRIMARY   4 test.playlist_media_files.media_file_id  1  Using where 

而且平均成績約爲:

Showing rows 0 - 29 (2,702 total, Query took 0.0359 sec) 

加入綜合指數和做後ANALYZE TABLE playlist_media_files解釋顯示:

1 SIMPLE playlist_media_files ref  playlist_id,media_file_id,playlist_media_composite playlist_media_composite 4 const          3925 Using index; Using temporary; Using filesort 
1 SIMPLE media_files    eq_ref PRIMARY            PRIMARY      4 test.playlist_media_files.media_file_id  1  Using where 

而且平均結果:

Showing rows 0 - 29 (2,702 total, Query took 0.0176 sec) 

然而,在這兩種情況下分選在內存中完成(仍然創造TMP表和排序發生在這裏80%的時間),看着你的分析截圖大部分時間是失去了對複製臨時表到光盤上。那是差異來自哪裏。我的表格只有這個查詢所需的列,並且可能我的隨機字符串不像您的那麼長,而您有更多的列,並且您正在選擇所有列,只在少數列上排序。所以你的臨時表不適合內存,顯然在光盤上做事情要慢很多。

因此,您的主要焦點應該是增加緩衝區大小以適應您的大選擇或限制列數以選擇可能不需要那麼多的列。

+0

分析:https://img.skitch.com/20120126-jphcihphpdigi6s48xysxig54g.jpg – kain

+0

我記得有這個組合鍵,並刪除它做一些測試,加回這個關鍵但是沒有明顯的性能收益,它仍然需要1775.3ms – kain

+0

用於說明嗎?什麼是你的MySQL版本? – piotrm

0

orderbys的含義是什麼?在這種情況下,在多個變量中使用它是沒有意義的。 爲什麼不直接訂購一件? 您可能會遇到數據庫設計規範化問題,您是否熟悉這一點?

+0

我想要初始化數據的表示,將已經排序的數據傳遞給底層的JSON解析器以供顯示。這就是爲什麼這樣排序。 – kain