2009-05-30 15 views
5

Ok、ここでは、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サーバをチョーク...それは何

がある - それは単に数を引きます登録済みの新規ユーザーのうち、少なくとも1つの「完了した」支払いがあり、tm_completedは空ではない(完了した支払いのためにのみ入力されるため)前払いの支払いをする前に - 新しいメンバーであることを意味します(単に借り替えなど)。これは、再払い戻された既存のメンバーと初めて請求された新しいメンバーを区別するための唯一の方法です) 。

ここで、少ないリソースや何かを使用するようにこのクエリを最適化し、自分のmysqlリソースを無駄にしないようにする方法はありますか?

私はこのことをさらに明確にするための情報がありませんか?私は...

EDITを知ってみましょう:

PRIMARY PRIMARY 46757

MEMBER_IDのINDEX 23378 MEMBER_ID

payer_id INDEX 11689 payer_id

をpayment_id:ここ

はすでにそのテーブル上のインデックスがあります

クーポンIDインデックス1クーポンID

tm_added INDEX 46757 tm_added、tm_completed

tm_completed INDEX 46757をPRODUCT_IDは、

+0

あなたは、検索引数が使用されているフィールドのインデックスを持っていますか – James

答えて

7

をPRODUCT_ID 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の速度は –

+0

うわー...それは私がすでに持っていたものからちょっとした変化であったことを知らなかった。「IN」を「EXISTS」に置き換えて...ありがとう! –

2

回避します。

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 

第二に、私が見なければならないでしょう:。これについては5.4と6.0での保留中の最適化がありますがMySQLが参加するとしてこれを書き換えることは、おそらくあなたのパフォーマンスの向上を取得します(hereを参照してください)(同様にこれらを最適化していませんあなたのテーブルスキーマ、あなたは、インデックスを使用している

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; 
+1

このテクニックは、mysql(歴史的にはサブクエリに問題があった)の中で特に効果的です。 – dkretz

+0

私はこの答えも好きです...明らかに、私がここで選んだ答えの両方でEXPLAINを実行すると、同じパフォーマンス/リソース使用率(「IN」サブクエリを使用しているときより約12,000倍高速な計算)が得られます。驚くばかり!ありがとうございました... –