2012-03-16 53 views
2

查詢:按結果優化查詢順序使用filesort;

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     pm_replies as r 
     LEFT JOIN users as u 
      ON u.uid = r.uid 
    WHERE 
     r.msg_id = '784351921943772258' 

    ORDER BY r.date DESC 

我嘗試了所有指標的組合我能想到的,在谷歌搜索如何盡我所能指數這一點,但沒有奏效。

這個查詢需要0,33上歸還物品和計數 ...


說明:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE r ALL  index1 NULL NULL NULL 540  Using where; Using filesort 
1 SIMPLE u eq_ref uid  uid  8 site.r.uid 1 

SHOW CREATE pm_replies

CREATE TABLE `pm_replies` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`reply_id` bigint(20) NOT NULL, 
`msg_id` bigint(20) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`body` text COLLATE utf8_unicode_ci NOT NULL, 
`date` datetime NOT NULL, 
PRIMARY KEY (`id`), 
KEY `index1` (`msg_id`,`date`,`uid`) 
) ENGINE=MyISAM AUTO_INCREMENT=541 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

SHOW創建用戶

CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`uid` bigint(20) NOT NULL, 
`username` varchar(20) COLLATE utf8_unicode_ci NOT NULL, 
`email` text CHARACTER SET latin1 NOT NULL, 
`password` text CHARACTER SET latin1 NOT NULL, 
`profile_picture` text COLLATE utf8_unicode_ci NOT NULL, 
`date_registered` datetime NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `uid` (`uid`), 
UNIQUE KEY `username` (`username`) 
) ENGINE=MyISAM AUTO_INCREMENT=2004 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 
+0

你可以添加'SHOW CREATE TABLE pm_replies','SHOW CREATE TABLE users','EXPLAIN SELECT <你的整個選擇在這裏>'的輸出嗎?除此之外,可能的索引將是'r.msg_id,r.uid',你會希望'u.uid'也有索引(最好唯一)。 – Konerak 2012-03-16 09:40:08

+0

@Konerak更新問題 – fxuser 2012-03-16 09:46:20

+0

你有索引u.uid,r.uid,r.msg_id和r.date嗎?編輯:我看到...嘗試索引日期pm_replies – 2012-03-16 09:46:26

回答

0

請試試這個:

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     pm_replies as r 
     LEFT JOIN users as u 
      ON (u.uid = r.uid AND r.msg_id = '784351921943772258') 
    ORDER BY r.date DESC 

在我的情況下,它幫助。

+0

相同的加載時間。 – fxuser 2012-03-16 09:43:08

+1

這在功能上是不同的,而且很可能是不正確的。 OP根據'msg_id'從'pm_replies'中獲取一組特定的行,然後將它們連接到'users'。 *(可能只是一行)*您從***_replies中取得所有***行,但只將它們連接到'用戶'作爲特定​​的'msg_id',所有其他所有行都通過,但是作爲NULL。這不是一個答案。 – MatBailie 2012-03-16 09:43:41

+0

您是否爲索引字段r.msg_id和r.date? – Mirodil 2012-03-16 09:44:20

5

對於查詢,因爲它是最好的指標,似乎是......

pm_replies: (msg_id, date, uid) 
users:  (uid) 

重要的一項是pm_replies。您可以使用它來過濾您的數據(首先是過濾器列),然後對數據進行排序(訂單欄位於第二位)。

如果您刪除了過濾器,則會有所不同。那麼你只需要(date, uid)作爲你的索引。

索引中的最後一個字段只是使其成爲聯接的一小部分,其重要部分實際上是users上的索引。

還有很多事情要說,關於這一點,至少在一本書中整整一章,如果你想要的話,還有幾本書。但我希望這有助於。


編輯

這並不是說我對pm_replies建議的指數是一個指數涵蓋三個方面,而不僅僅是三個指標。這確保索引中的所有條目都按這些列進行了預先排序。這就像在Excel中按三列分類數據一樣。

有三個單獨的索引就像有三個選項卡上的Excel數據。每個按不同的字段排序。

只有在三個字段上有一個索引纔會得到此行爲...
- 你可以用相同的MSG_ID
選擇一個記錄「一堆」 - 這整個「一堆」是彼此相鄰,沒有間隙,等
- 即整個「一堆」日期順序排列爲MSG_ID
- 對於具有相同日期的任何行,它們是由USER_ID下令

(同樣user_ID的一部分真的是很微小的。)

+1

+1,日期是我認爲的關鍵。 – davidethell 2012-03-16 09:55:11

+0

所以你說要創建3列3索引?如果是這樣,這似乎仍然沒有幫助。 – fxuser 2012-03-16 09:59:16

+0

已更新EXPLAIN和SHOW CREATE TABLE的回覆 – fxuser 2012-03-16 10:06:42

0

日期加到您的索引1鍵,以便MSG_ID和日期都是該指數。

+0

仍然沒有任何變化 – fxuser 2012-03-16 09:56:52

0

什麼Dems is saying應該是正確的,但有一個額外的細節,如果你正使用InnoDB:也許你付出的secondary indexes on clustered tables價格 - 從本質上講,通過二級索引訪問行需要額外查找槽小學,即聚類索引。這種「雙查找」可能會使索引對查詢優化器的吸引力下降。

爲了緩解這個問題,嘗試covering所有字段在SELECT語句與指數:

pm_replies: (msg_id, date, uid, reply_id, body, date) 
users:  (uid, username, profile_picture) 
+0

我所有的表都是myisam,我改爲innodb只是爲了測試dems的評論。 – fxuser 2012-03-16 11:34:31

+0

@fxuser還有一件事:您是否嘗試過使用索引pm_replies:(msg_id,uid)',因爲這是一個左連接,'users'是「外」表。另外,你是否嘗試移除LEFT,只是爲了看看會發生什麼? – 2012-03-16 12:18:25

+0

@fxuser甚至是'pm_replies:(uid,msg_id)'? – 2012-03-16 12:28:03

0

看起來優化器試圖強行通過ID索引,使加入的用戶表。由於你正在做一個左連接(這是沒有意義的,因爲我期望每個條目都有一個用戶ID,因此是一個正常的INNER JOIN),所以我會保持它的左連接。

所以,我會嘗試以下。查詢只是基於通過對自己的優點日期下降的消息ID和順序的答覆,然後離開加盟,如

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     (select R2.* 
      from pm_replies R2 
      where r2.msg_id = '784351921943772258') r 
     LEFT JOIN users as u 
      ON u.uid = r.uid 
    ORDER BY 
     r.date DESC 

另外,由於我沒有MySQL的隨手可得,而不能記住子查詢中是否允許排序,如果是這樣,您可以優化內部預查詢(使用別名「R2」)並在那裏放置順序,因此它使用(msgid,date)索引並返回該集合...然後,從源結果集中加入到用戶表上的用戶表上沒有索引所需的ID,只是用戶表上的索引來查找匹配。

+0

這需要更長的時間才能加載並在2列(msg_id,date)上添加1個索引也不會起作用。 – fxuser 2012-03-16 13:34:29

+0

@fxuser,對不起,它不起作用,但你總是必須嘗試替代引擎可能的想法。這是一個簡單的測試,要麼工作得更快,要麼更快。只是尋找性能改進的衆多方法之一。 – DRapp 2012-03-16 13:43:51

相關問題