質問

さて、これは私が現在 45,000 レコードを持ち、サイズが 65MB のテーブルに対して実行しているクエリです...そして、それはますます大きくなりつつあります(したがって、ここでは将来のパフォーマンスについても考慮する必要があります)。

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 が空ではなく (完了した支払いに対してのみ入力されるため)、そのメンバーが持っている (埋め込まれた Select) 新規ユーザーの数を取得するだけです。これまでに支払いが「完了」したことがない - つまり、その人は新規メンバーです (システムが再請求などを行うためです。これが、再請求されたばかりの既存メンバーと請求された新規メンバーを区別する唯一の方法だからです)初めて)。

さて、このクエリを最適化してリソースの使用量を減らしたり、mysql リソースを圧迫しないようにする方法はありますか?

これをさらに明確にするための情報が不足しているのでしょうか?お知らせ下さい...

編集:

そのテーブルにすでに存在するインデックスは次のとおりです。

PRIMARY PRIMARY 46757payment_id

メンバーID INDEX 23378 メンバーID

支払者 ID INDEX 11689 支払者 ID

クーポンID INDEX 1 クーポンID

tm_added INDEX 46757 tm_added、product_id

tm_completed INDEX 46757 tm_completed、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');
それはあなたのtm_completed IS NOT NULL条件によって暗示されるように、

チェック「BETWEENは」必要はありません。

また、あなたは上のインデックスを持っていることを確認します:

(tm_completed, completed)

他のヒント

私は楽しみにサブクエリを必要としないこの解決策を一緒に入れていました

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;

サブクエリで IN を使用することは避けてください。MySQL はこれらを十分に最適化しません (ただし、これに関して 5.4 および 6.0 には保留中の最適化があります (「 ここ)。これを結合として書き直すと、おそらくパフォーマンスが向上します。

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

次に、テーブル スキーマを確認する必要があります。インデックスを使用していますか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top