2010-08-19 47 views
7

Tôi có truy vấn UNION bao gồm hai truy vấn nhanh.Truy vấn UNION chậm - 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') 

Trước các truy vấn chạy trong 0.0047s Thứ hai chạy trong 0.0043s

Tuy nhiên, với Liên minh, họ chạy 0.27s ... tại sao điều này là gì? Không có Order By sau UNION, tại sao MySQL không đơn giản lấy hai truy vấn nhanh và ghép chúng lại?

Trả lời

2

Thử sử dụng UNION ALL.

UNION sẽ tự xóa mọi bản ghi trùng lặp, ngụ ý sắp xếp hậu trường.

+0

UNION ALL giảm nó xuống 0,17s .. nó đã làm một cái gì đó, nhưng nó vẫn còn quá chậm :(.. cảm ơn cho câu trả lời mặc dù :) – Armin

11

A UNION làm cho bảng tạm thời được tạo, ngay cả đối với UNION ALL.

Khi một UNION DISTINCT (tương tự như UNION) được thực hiện, bảng tạm thời được tạo bằng chỉ mục sao cho các bản sao có thể bị xóa. Với UNION ALL, bảng tạm thời được tạo, nhưng không có chỉ mục.

Điều này giải thích cải thiện hiệu suất nhỏ khi sử dụng UNION ALL và cũng giảm tài khoản khi sử dụng UNION thay vì hai truy vấn riêng biệt.

Để biết thêm thông tin về vấn đề này, vui lòng xem sau trên MySQL performance blog:

UNION vs UNION ALL Performance

Các How MySQL Uses Internal Temporary Tables trang từ các tài liệu MySQL khẳng định rằng một bảng tạm thời được tạo ra khi:

. .. bất kỳ cột nào lớn hơn 512 byte trong danh sách SELECT, nếu UNION hoặc UNION ALL được sử dụng

+0

Cảm ơn lời giải thích :). Rất hữu ích về kiến ​​thức, nhưng không giúp tôi giải quyết được vấn đề của mình. Tôi về cơ bản đang cố gắng để có được tất cả các truy vấn của tôi được tối ưu hóa. Với tôi, bất kỳ truy vấn nào chạy chậm hơn 0,1 đều là một vấn đề. Tôi có một trang web lớn với rất nhiều khách truy cập và không thể đủ khả năng để có một truy vấn như thế này chạy ở 0,17s. Cho đến nay, đặt cược tốt nhất của tôi là chỉ cần chạy hai truy vấn và hợp nhất các mảng kết quả với PHP, điều này khá mô-đun-khôn ngoan. – Armin

+0

@Armin: Tôi đồng ý, nó không giúp được gì nhiều. Tôi nhận thấy rằng cả hai truy vấn của bạn rất giống nhau - chúng có thể được kết hợp thành một câu lệnh 'SELECT' duy nhất không? Chúng khác nhau trong điều kiện 'WHERE', và có vẻ như điều này có thể được giảm xuống bằng cách sử dụng một vài toán tử' OR'. Vấn đề duy nhất tôi thấy (và tôi chỉ có một cái nhìn nhanh) là sự trở lại của bạn 'uuxr.intUserId1 AS intUserId' và' uuxr.intUserId2 AS intUserId'. Có lẽ bạn có thể sử dụng một 'IF' để chọn cột đúng để trả về từ một câu lệnh đơn. – Mike

+0

Tôi đã có điều này trước đây. Truy vấn sẽ rất chậm. Đây là một ví dụ. Tôi thiết lập một giới hạn chỉ có 5 hồ sơ ở đây và nó chạy cho 0,47s. 'CHỌN u.intUserId, u.strUserName TỪ Urlr User_User_XR, Người dùng u Ở ĐÂU (uuxr.intUserId1 = '1' VÀ uuxr.intUserId2 = u.intUserId) HOẶC (uuxr.intUserId2 = '1' AND uuxr.intUserId1 = u. intUserId) VÀ uuxr.strStatus = 'confirm' LIMIT 5' – Armin

Các vấn đề liên quan