2010-08-19 190 views
7

我有一個由兩個快速查詢組成的UNION查詢。緩慢UNION查詢 - MySQL

(SELECT DISTINCT (SELECT strStatus FROM User_User_XR uuxr WHERE 
(uuxr.intUserId1 = '1' AND uuxr.intUserId2 = u.intUserId)) AS strFriendStatus1, 
uuxro.strStatus AS strFriendStatus2, uuxr.intUserId2 AS intUserId, u.strUserName , 
u.strGender, IF(u.dtmBirth != '0000-00-00', FLOOR(DATEDIFF(CURDATE(), 
u.dtmBirth)/365.25) , '?') AS intAge, u.strCountry AS strCountryCode, 
c.strCountry AS strCountry, u.strAvatar, u.fltPoints, 
IF(o.intUserId IS NULL, 'offline', 'online') AS strOnline, 
IF (u.strAvatar != '', CONCAT('avatars/60/', u.strAvatar), 
CONCAT('images/avatar_', u.strGender, '_small.png')) as strAvatar,  
IF (u.strAvatar != '', CONCAT('avatars/150/', u.strAvatar),  
CONCAT('images/avatar_', u.strGender, '.png')) as strLargeAvatar, 
u.dtmLastLogin, u.dtmRegistered FROM User_User_XR uuxr, 
User u LEFT JOIN User_User_XR uuxro ON uuxro.intUserId2 = '1' 
AND uuxro.intUserId1 = u.intUserId 
LEFT JOIN Online o ON o.intUserId = u.intUserId 
LEFT JOIN Country c ON c.strCountryCode = u.strCountry 
WHERE u.intUserId = uuxr.intUserId2 AND (uuxr.strStatus = 'confirmed') 
AND uuxr.intUserId1='1') 

UNION 

(SELECT DISTINCT (SELECT strStatus FROM User_User_XR uuxr 
WHERE (uuxr.intUserId1 = '1' AND uuxr.intUserId2 = u.intUserId)) AS strFriendStatus1, 
uuxro.strStatus AS strFriendStatus2, uuxr.intUserId1 AS intUserId, u.strUserName , 
u.strGender, IF(u.dtmBirth != '0000-00-00', FLOOR(DATEDIFF(CURDATE(), 
u.dtmBirth)/365.25) , '?') AS intAge, 
u.strCountry AS strCountryCode, c.strCountry AS strCountry, u.strAvatar, u.fltPoints, 
IF(o.intUserId IS NULL, 'offline', 'online') AS strOnline, 
IF (u.strAvatar != '', CONCAT('avatars/60/', u.strAvatar), 
CONCAT('images/avatar_', u.strGender, '_small.png')) as strAvatar, 
IF (u.strAvatar != '', CONCAT('avatars/150/', u.strAvatar), 
CONCAT('images/avatar_', u.strGender, '.png')) as strLargeAvatar, 
u.dtmLastLogin, u.dtmRegistered FROM User_User_XR uuxr, User u 
LEFT JOIN User_User_XR uuxro ON uuxro.intUserId2 = '1' 
AND uuxro.intUserId1 = u.intUserId 
LEFT JOIN Online o ON o.intUserId = u.intUserId 
LEFT JOIN Country c ON c.strCountryCode = u.strCountry 
WHERE u.intUserId = uuxr.intUserId1 AND (uuxr.strStatus = 'confirmed') 
AND uuxr.intUserId2='1') 

查詢首先在0.0047s 二運行運行在0.0043s

然而,與工會,他們跑0.27s ......這是爲什麼?在UNION之後沒有Order By,爲什麼MySQL不會簡單地使用這兩個快速查詢並將它們連接起來?

回答

2

嘗試使用UNION ALL

UNION自己將刪除任何重複記錄,這意味着幕後排序。

+0

聯盟所有減少到0.17s ..它做了一些事情,但它仍然太慢... :(謝謝答案:) – Armin 2010-08-19 17:54:47

11

A UNION導致創建一個臨時表,即使對於UNION ALL

當執行UNION DISTINCT(與UNION相同)時,將使用索引創建臨時表,以便刪除重複項。用UNION ALL,臨時表被創建,但沒有索引。

這解釋了使用UNION ALL時的輕微性能改進,並說明了使用UNION而不是兩個單獨查詢時的性能下降。

有關它的更多信息,請參閱MySQL performance blog以下條目:從MySQL文檔

UNION vs UNION ALL Performance

How MySQL Uses Internal Temporary Tables頁指出,一個臨時表創建時:

。 ..如果使用UNION或 UNION ALL,則在SELECT列表中大於512 字節的任何列

+0

感謝您的解釋:)。非常有用的知識智慧,但沒有讓我進一步解決我的問題。我基本上試圖讓我所有的查詢優化。對我來說,任何運行速度低於0.1的查詢都是一個問題。我有一個很大的訪問者的大型網站,不能承受這樣的查詢運行在0.17s。到目前爲止,我最好的辦法就是運行兩個查詢並將結果數組與PHP合併,這非常模塊化。 – Armin 2010-08-19 19:08:18

+0

@Armin:我同意,這並沒有多大幫助。我注意到你的查詢都非常相似 - 它們是否可以組合成一個「SELECT」語句?它們在'WHERE'條件中有所不同,看起來好像可以通過使用幾個'OR'運算符來減少它。我看到的唯一的其他問題(我只能快速瀏覽一下)就是返回'uuxr.intUserId1 AS intUserId'和'uuxr.intUserId2 AS intUserId'。也許你可以使用'IF'來選擇正確的列從單個語句返回。 – Mike 2010-08-19 20:30:54

+0

我曾經這樣做過。該查詢將非常緩慢。這是一個例子。我在這裏設置了5條記錄的限制,它運行了0.47s。 (uuxr.intUserId1 ='1'且uuxr.intUserId2 = u.intUserId)或(uuxr.intUserId2 ='1'並且uuxr.intUserId1 = u。)用戶u用戶u用戶u用戶用戶名u。 intUserId)和uuxr.strStatus ='確認'LIMIT 5' – Armin 2010-08-20 06:17:07