2009-05-30 30 views
5

好的,這裏是一個查詢,我現在正在一個擁有45,000條記錄並且大小爲65MB的表上運行......並且正在變得越來越大(所以我必須考慮未來的表現,以及在這裏)的:在mySQL中優化嵌入式SELECT查詢

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) 

正如你可能會或可能不會想象 - 它扼流圈MySQL服務器癱瘓......

它所做的是 - 它只是拉數的新用戶註冊,至少有一個「已完成」的付款,tm_completed不是空的(因爲它只填充已完成的付款),以及(嵌入式選擇)成員從未擁有過「com完成「付款 - 這意味着他是一個新成員(僅僅是因爲系統確實會重新投入,而且這是區分剛剛獲得回扣的現有成員和第一次收到新成員的新成員之間唯一的區別) 。

現在,是否有任何可能的方式來優化此查詢使用更少的資源或什麼,並停止採取我的MySQL資源跪下......?

我是否缺少任何信息以進一步澄清此問題?讓我知道...

編輯:

這裏有指標已經在該表:

PRIMARY PRIMARY 46757 payment_id

member_id INDEX 23378 member_id

payer_id INDEX 11689 payer_id

coupon_id INDEX 1 coupon_id

tm_added INDEX 46757 tm_added,PRODUCT_ID

tm_completed INDEX 46757 tm_completed,PRODUCT_ID

+0

你對其中正在使用搜索ARGS領域指標 – James 2009-05-30 05:20:06

回答

7

像這樣的IN子查詢是在MySQL有點慢。我會改寫這樣的:

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'); 

爲由您BETWEEN條件所暗示的支票「tm_completed IS NOT NULL」是沒有必要的。

另外,還要確保你有一個索引:使用與子查詢

(tm_completed, completed) 
+0

打我?到衝牀; +1爲速度 – 2009-05-30 05:25:10

+0

哇...不知道這只是我已經做出的一些小改動,只是將「IN」替換爲「EXISTS」..​​....謝謝! – 2009-05-30 15:30:01

2

避免; MySQL不優化這些好(雖然有5.4和6.0未決優化對此(見here),改寫本作爲聯接可能會得到你的性能提升。

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 

其次,我將不得不看你的表模式,您使用的指標

7

我很開心組建這個解決方案,它不需要子查詢:

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;