2017-01-03 12 views
2

私は1100000レコードを持つテーブルuser_notificationsを持っていますが、これを下のクエリで実行する必要がありますが、フェッチ時間を改善するために何ができるのですか?このSQLクエリをより速くするにはどうすればよいですか?

SELECT `user_notifications`.`user_id` 
FROM `user_notifications` 
WHERE `user_notifications`.`notification_template_id` = 175 
AND (DATE(sent_at) >= DATE_SUB(CURDATE(), INTERVAL 4 day)) 
AND `user_notifications`.`user_id` IN (
    1203, 1282, 1499, 2244, 2575, 2697, 2828, 2900, 3085, 3989, 
    5264, 5314, 5368, 5452, 5603, 6133, 6498.. 
) 

INブロックのユーザーIDは1kになることがあります。

私はuser_idnotification_template_idの欄にuser_notificationという表の索引を付けました。

enter image description here

+1

1 + 100万レコードの 'user_id'値を1000個比較すると、MySQLが必要に応じてインデックスを使用していても、時間がかかることになります。どのくらいの年齢ですか? –

+0

@TimBiegeleisen 2-5 minutes avg – Prem

+0

user_idとnotification_template_idに別々のインデックスを作成しましたか、どちらか一方に別のインデックスを作成しましたか?後者を試してみてください。 – wumpz

答えて

7

大きなIN()リストは本質的に遅いです。インデックス付きのテンポラリテーブルを作成し、そのテンポラリテーブルにIN()リストの値を代入すると、巨大なIN()リストの代わりにインデックス付き結合の力が得られます。

+0

ありがとう@Danそれは論理的ですね。私はsend_atフィールドのためにできることがあるかどうか教えてください。これもまたクエリの遅延を引き起こしていると思います。 – Prem

+0

@Premあなたはその意見を支持するための事実はありますか? codeforesterはそれに対処しており、その答えに対する私のコメントも関連しています。しかし、あなたのIN句は、遅延の大半を引き起こしていることはほぼ確実です。 –

+0

'IN()'では70Kの項目で問題が発生しましたが、1Kでは問題がありません。 –

2

あなたは小さな日付範囲を照会しているようです。 SENT_AT列に基づくインデックスはどうですか?現在のクエリが使用しているインデックスを知っていますか?

+2

そのテーマでは、 'sent_at'を実際にDATEに変換する必要がありますか? DATE(sent_at)が指定された値より大きい場合、sent_at自体は少なくともそれ以上大きくなければならないので、そのキャストを取り除くようなことは同じ結果をもたらすでしょう。 –

+2

@DanFarrell 100%の確信はありませんが、1000ユーザーIDの比較はこのクエリを強制終了するものです。 –

+1

DATE(sent_at)は、関数呼び出しのためにsent_atベースのインデックスの使用を妨げる可能性があるため、問題になる可能性があります。 – codeforester

1

(1)あなたは、インデックスを使用する必要がある可能性がある場合の関数で列を非表示にしないでください。

AND (DATE(sent_at) >= DATE_SUB(CURDATE(), INTERVAL 4 day)) 

- >

AND sent_at >= CURDATE() - INTERVAL 4 day 

(2)のための "複合" のインデックスを使用します

WHERE `notification_template_id` = 175 
    AND sent_at >= ... 
    AND `user_id` IN (...) 

最初の列は '='の列である必要があります。次に何を入れるべきかは不明です。これらのインデックスを両方追加することをお勧めします。

INDEX(notification_template_id, user_id, sent_at) 
INDEX(notification_template_id, sent_at) 

オプティマイザはおそらくそれらの間を正しく選択します。

複合インデックスは、ではありません。個々の列のインデックスと同じです。

(0) INリストをtmpテーブルに入れてみてください。ただし、そのような処理を行うコストが利益を上回る可能性があります。私はIN()の1K値が「あまりにも多い」とは考えていません。

(4)My cookbook建物インデックス。

+0

composite_index INDEX(notification_template_id、user_id、sent_at)を作成する必要がある場合は、別々のインデックスを削除する必要がありますか? – Prem

+0

このように考えてみましょう...名前のリストが姓でソートされている場合、_just_ファーストネームで誰かを検索することは不可能です。したがって、他のインデックスは削除しないでください(最初に他のインデックスが必要でないことは発見されていません)。 –

+0

私のインデックスは_other_クエリに役立つかもしれません。 –

関連する問題