2013-01-05 35 views
6

Dưới đây là một câu lệnh SQL bên trong một thủ tục lưu trữ (cắt ngắn cho ngắn gọn):MySQL Ở ĐÂU KHÔNG TRONG cực kỳ chậm

SELECT * 
FROM item a 
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item); 

Tuyên bố này mất 30 giây hoặc lâu hơn! Nhưng nếu tôi xóa truy vấn SELECT bên trong, nó sẽ giảm xuống 1s. table_excluded_item không phải là rất lớn, nhưng tôi nghi ngờ các truy vấn bên trong đang được thực hiện nhiều hơn nó cần phải được.

Có cách nào hiệu quả hơn để thực hiện việc này không?

+1

Truy vấn bên trong là truy vấn con phụ thuộc, vốn là nút cổ chai khét tiếng vì truy vấn con chạy trên mỗi hàng truy vấn bên ngoài. Kiểm tra [Tối ưu hóa truy vấn con] (http://dev.mysql.com/doc/refman/5.1/en/optimizing-subqueries.html) trên trang web dev của MySQL. – Anthony

Trả lời

14

sử dụng LEFT JOIN

SELECT a.* 
FROM item a 
     LEFT JOIN table_excluded_item b 
      ON a.orderId = b.orderId 
WHERE b.orderId IS NULL 

chắc chắn rằng orderId từ hai bảng đã được lập chỉ mục.

+0

Xin chào, cảm ơn! Bây giờ nó xuống đến 2s. Ngôn ngữ luôn có vẻ rất phản trực giác với tôi: ( – pixelfreak

+0

bạn được chào đón ': D' –

1

Hãy thử điều này và so sánh với thời gian LEFT JOIN truy vấn:

SELECT * 
FROM item a 
HAVING orderId NOT IN (SELECT orderId FROM table_excluded_item); 

này được tán thành (sử dụng HAVING khi WHERE có thể được sử dụng) từ HAVING giả định rằng các điều kiện hạn chế (orderId) là một phần của kết quả bộ. Nhưng tôi nghĩ rằng trong kịch bản này nó có ý nghĩa hơn (vì nó là một phần của tập kết quả) và bởi vì nó là rõ ràng hơn những gì đang xảy ra hơn cách tiếp cận LEFT JOIN.

Nó thực sự có thể chậm hơn một chút, nhưng đăng kết quả để chúng tôi biết liệu có tốt hơn truy vấn ban đầu của bạn hay không.

+0

cổ vũ - trên tập dữ liệu của tôi, tôi luôn nhận được ~ 7 giây cho điều này so với 8 giây cho phương pháp tiếp cận bên trái – hoju

5

Sự cố với phương pháp nối bên trái là bản ghi trùng lặp có thể được xử lý trong việc tạo đầu ra. Đôi khi, đây không phải là trường hợp. . . theo điều này article, MySQL tối ưu hóa chính xác left outer join khi các cột được lập chỉ mục, ngay cả khi có sự trùng lặp. Tôi thừa nhận vẫn còn hoài nghi, mặc dù, rằng tối ưu hóa này luôn luôn xảy ra.

MySQL đôi khi gặp sự cố khi tối ưu hóa IN câu lệnh với truy vấn phụ. Việc sửa chữa tốt nhất là một subquery tương quan:

SELECT * 
FROM item a 
WHERE not exists (select 1 
        from table_excluded_item tei 
        where tei.orderid = a.orderid 
        limit 1 
       ) 

Nếu bạn có một chỉ mục trên table_excluded_item.orderid, thì điều này sẽ quét các chỉ mục và dừng lại ở giá trị đầu tiên (limit 1 có thể không thực sự cần thiết cho việc này). Đây là cách nhanh nhất và an toàn nhất để thực hiện những gì bạn muốn trong MySQL.

+2

Về mặt kỹ thuật, giới hạn 1 là không cần thiết, các "chống tham gia" sẽ làm chính xác cùng một điều anyway. (Nó * có thể được * mysql là không đủ thông minh để biết điều này) – wildplasser

+0

"Vấn đề với cách tiếp cận tham gia trái là bạn có thể nhận được bản ghi trùng lặp trong đầu ra. "- tại sao? hãy nhớ rằng bạn đang tìm kiếm bản ghi không tồn tại. –

+0

@jW ... Tôi đã lặp lại điều này. –

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