2010-08-19 9 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.27s를 실행 연합과, 그러나

0.0043s에서 실행 ...이 왜? UNION 다음에는 Order By가 없습니다. 왜 MySQL이 두 개의 빠른 쿼리를 가져 와서 연결하지 않을까요?

답변

2

UNION ALL을 사용해보세요.

UNION은 자체 기록을 제거하므로 배후의 정렬을 의미합니다.

+0

UNION ALL은 그것을 0.17s로 줄였습니다. 그것은 뭔가를했지만 아직도 너무 느립니다 : (.. 대답을 주셔서 감사합니다 :) – Armin

11

UNIONUNION ALL의 경우에도 임시 테이블이 만들어집니다.

(이는 UNION과 동일 함)이 수행되면 중복을 제거 할 수 있도록 인덱스가있는 임시 테이블이 만들어집니다. UNION ALL을 사용하면 임시 테이블이 작성되지만 인덱스는 작성하지 않습니다.

이렇게 두 개의 별도 쿼리 대신 UNION을 사용하면 성능 저하가 발생하며, UNION ALL을 사용하면 성능이 약간 향상됩니다.

: 임시 테이블이 때 생성되는 내용의 MySQL의 문서에서

UNION vs UNION ALL Performance

How MySQL Uses Internal Temporary Tables 페이지 :

이에 대한 자세한 내용은 MySQL performance blog에서 다음 항목을 참조하십시오. UNION 또는 UNION ALL을 사용하는 경우 SELECT 목록의 512 바이트보다 큰 열

+0

설명 주셔서 감사합니다 :). 매우 지식이 많지만 내 문제를 해결하는 데 도움이되지 않습니다. 기본적으로 모든 쿼리를 최적화하려고합니다. 저에게 0.1보다 느리게 실행되는 쿼리는 문제입니다. 나는 많은 방문자가있는 큰 사이트를 가지고 있으며, 위와 같은 쿼리를 0.17 초에 실행하는 것에는 여유가 없다. 지금까지 두 가지 쿼리를 실행하고 결과 배열을 PHP로 병합하는 것이 가장 바람직합니다. PHP는 상당히 못생긴 모듈 방식입니다. – Armin

+0

@Armin : 동의합니다.별로 도움이되지 않습니다. 두 쿼리가 매우 유사하다는 것을 알았습니다 - 단일 SELECT 문에 결합 될 수 있습니까? 그것들은'WHERE' 조건이 다르며,'OR' 연산자 몇 개를 사용하여 줄일 수있는 것처럼 보입니다. 제가보기에 유일한 다른 문제는'uuxr.intUserId1 AS intUserId'와'uuxr.intUserId2 AS intUserId'입니다. 아마도 'IF'를 사용하여 단일 문에서 반환 할 올바른 열을 선택할 수 있습니다. – Mike

+0

나는 이것을 전에 가지고 있었다. 쿼리가 매우 느립니다. 다음은 그 예입니다. 나는 여기에 단지 5 개의 레코드 한도를 설정하고 그것은 0.47s에 대해 실행됩니다. (uuxr.intUserId1 = '1'AND uuxr.intUserId2 = u.intUserId) 또는 (uuxr.intUserId2 = '1'AND uuxr.intUserId1 = u.)를 입력하십시오. intUserId) 및 uuxr.strStatus = 'confirmed'LIMIT 5' – Armin