2010-08-19 151 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