2009-05-30 36 views
5

Ok, đây là truy vấn mà tôi đang chạy ngay trên bảng có 45.000 bản ghi và có kích thước 65MB ... và sắp trở nên lớn hơn và lớn hơn (vì vậy tôi phải suy nghĩ việc thực hiện trong tương lai cũng ở đây):Tối ưu hóa truy vấn SELECT được nhúng trong mySQL

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount 
FROM payments p 
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30' 
AND completed > 0 
AND tm_completed IS NOT NULL 
AND member_id NOT IN (SELECT p2.member_id FROM payments p2 WHERE p2.completed=1 AND p2.tm_completed < '2009-05-01' AND p2.tm_completed IS NOT NULL GROUP BY p2.member_id) 

Và như bạn có thể hoặc có thể không tưởng tượng - nó nghẹn server mysql rơi vào bế tắc ...

những gì nó là - nó chỉ đơn giản kéo số của người dùng mới đã đăng ký, có ít nhất một khoản thanh toán "đã hoàn tất", tm_completed không trống (vì nó chỉ được điền cho các khoản thanh toán đã hoàn thành) và (Chọn được chọn) mà thành viên chưa bao giờ có "com pleted "thanh toán trước - nghĩa là anh ấy là thành viên mới (chỉ vì hệ thống thực hiện rebills và whatnot, và đây là cách duy nhất để phân biệt giữa thành viên hiện có vừa được trả lại và thành viên mới được lập hóa đơn lần đầu tiên) .

Bây giờ, có cách nào có thể để tối ưu hóa truy vấn này để sử dụng ít tài nguyên hơn hay gì đó, và ngừng sử dụng tài nguyên mysql trên đầu gối của họ ...?

Tôi có thiếu thông tin nào để làm rõ thêm điều này nữa không? Hãy cho tôi biết ...

EDIT:

Dưới đây là các chỉ số đã có trên bảng:

TIỂU TIỂU 46.757 payment_id

member_id INDEX 23.378 member_id

payer_id INDEX 11.689 payer_id

coupon_id INDEX 1 coupon_id

tm_added INDEX 46.757 tm_added, product_id

tm_completed INDEX 46.757 tm_completed, product_id

+0

bạn có chỉ số trên các lĩnh vực nơi args tìm kiếm đang được sử dụng – James

Trả lời

7

Những loại IN truy vấn con là một chút chậm trong MySQL. Tôi sẽ nói lại nó như thế này:

SELECT COUNT(1) AS signup_count, SUM(amount) AS signup_amount 
FROM payments p 
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30' 
AND completed > 0 
AND NOT EXISTS (
      SELECT member_id 
      FROM payments 
      WHERE member_id = p.member_id 
      AND completed = 1 
      AND tm_completed < '2009-05-01'); 

Vui lòng cung 'tm_completed IS NOT NULL' là không cần thiết như vốn được gợi ý tình trạng BETWEEN của bạn.

Ngoài ra hãy chắc chắn rằng bạn có một chỉ mục trên:

(tm_completed, completed) 
+0

đánh bại tôi? với cú đấm, +1 cho tốc độ –

+0

Chà ...không biết nó chỉ là một thay đổi nhỏ so với những gì tôi đã có, chỉ cần thay thế "IN" cho "EXISTS" ... cảm ơn bạn! –

2

Tránh sử dụng IN với một subquery; MySQL không tối ưu hóa các tốt (mặc dù có đang chờ tối ưu hóa trong 5.4 và 6.0 về vấn đề này (xem here) Viết lại này như một join có thể sẽ giúp bạn có được một tăng hiệu suất:.

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount 
FROM payments p 
LEFT JOIN (SELECT p2.member_id 
      FROM payments p2 
      WHERE p2.completed=1 
      AND p2.tm_completed < '2009-05-01' 
      AND p2.tm_completed IS NOT NULL 
      GROUP BY p2.member_id) foo 
ON p.member_id = foo.member_id AND foo.member_id IS NULL 
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30' 
AND completed > 0 
AND tm_completed IS NOT NULL 

Thứ hai, tôi sẽ phải xem schema bảng của bạn, bạn đang sử dụng chỉ số

7

tôi đã vui vẻ đặt lại với nhau giải pháp này mà không đòi hỏi một subquery:

SELECT count(p1.payment_id) as signup_count, 
     sum(p1.amount)  as signup_amount 

    FROM payments p1 
     LEFT JOIN payments p2 
     ON p1.member_id = p2.member_id 
    AND p2.completed = 1 
    AND p2.tm_completed < date '2009-05-01' 

WHERE p1.completed > 0 
    AND p1.tm_completed between date '2009-05-01' and date '2009-05-30' 
    AND p2.member_id IS NULL; 
+1

Kỹ thuật này có hiệu quả đáng tin cậy đặc biệt là trong mysql (mà trước đây đã gặp sự cố với các truy vấn phụ). – dkretz

+0

Tôi thích câu trả lời này ... rõ ràng, khi chạy EXPLAIN trên cả hai câu trả lời tôi chọn ở đây, tôi nhận được hiệu suất/sử dụng tài nguyên giống nhau (tính toán nhanh hơn khoảng 12.000 lần so với khi sử dụng truy vấn con "IN"). Tuyệt vời! Cảm ơn bạn... –

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