2017-06-06 4 views
-1

次のクエリは、 'areacode.hours = 2'を追加する場合を除いて、すぐに実行されます。もう1秒かかるのではなく、1分近くかかります。WHEREにJOINを追加すると、MySQLクエリが非常に遅くなります

SELECT lead.id, first, last, lead.phone, valid_phone, mobile_phone 
FROM lead 
LEFT JOIN dnt ON dnt.phone = lead.phone 
LEFT JOIN areacode ON areacode.code = LEFT(lead.phone, 3) 
LEFT JOIN campaign ON campaign.id = lead.campaign_id 
WHERE dnt.id IS NULL 
AND campaign.lft BETWEEN 0 AND 1000 
AND lead.datetime BETWEEN '2017-06-01 00:00:00' AND '2017-06-01 23:59:59' 
AND areacode.hours = 2 
GROUP BY lead.phone 
ORDER BY lead.phone DESC 
LIMIT 1,1000 

結果は、EXPLAIN

1 SIMPLE lead index campaign_id,datetime phone 13 NULL 181181 Using where 
1 SIMPLE campaign eq_ref PRIMARY PRIMARY 4 data3_db.lead.campaign_id 1 Using where 
1 SIMPLE areacode ref code,hours code 11 func 1 Using index condition; Using where 
1 SIMPLE dnt ref phone phone 12 data3_db.lead.phone 1 Using where; Using index; Not exists 
+0

1. EXPLAINを使用してインデックスの使用状況を確認する/ 2. areacode.hoursにインデックスを追加する – Jan

+0

クエリで 'EXPLAIN'を実行する必要があります。私の頭の上から、 'areacode.hours'にインデックスを追加するとここで助けになるでしょう。 –

+0

@TimBiegeleisenここで興味があるのは、なぜareacode.hoursにインデックスを追加するのですが、他のフィールドは追加しませんか?私はインデックスを作成するのが初めてです。 –

答えて

0

あなたの完全参加した後句の制限が実行されています。これにより、左結合がINNER結合のように動作します。これらのテーブルの制限を、左側の結合の右側に移動することをお勧めします。結合が発生する前に制限が適用されます。 (またはその一部として)

フィールドでNullをチェックしている場合は例外です。それはwhere句に残る可能性があります。テーブル内のnullであるdnt.idとwhere句に入れた場合には左の結合の一部としてnullであるdnt.idを区別する方法はありません。しかし、これが「ID」フィールドであるとすれば、nullにすることはできず、どこに意味を残すことができると仮定します。

数千のレコードがあるときに、コンパイラは結合後にフィルタを適用しようとすることがあります。結合の前/後に制限を移動することにより、エンジンはレコードをフィルタリングする前に構築しなければならない一時的なデータセットを減らすことができます。内部結合ではこれは重要ではありませんが、外部結合ではパフォーマンスに影響するだけではありません。望ましい結果をもたらす。

SELECT lead.id, first, last, lead.phone, valid_phone, mobile_phone 
FROM lead 
LEFT JOIN dnt 
    ON dnt.phone = lead.phone 
LEFT JOIN areacode 
    ON areacode.code = LEFT(lead.phone, 3) 
AND areacode.hours = 2 
LEFT JOIN campaign 
    ON campaign.id = lead.campaign_id 
AND campaign.lft BETWEEN 0 AND 1000 
WHERE lead.datetime BETWEEN '2017-06-01 00:00:00' AND '2017-06-01 23:59:59' 
    AND dnt.id IS NULL 
GROUP BY lead.phone 
ORDER BY lead.phone DESC 
LIMIT 1,1000 

これでも希望の結果と時間が得られない場合は、希望のインデックスを調べます。

+0

私は彼らが私の場合に内部結合になる必要があると信じています。私は0から1000の間のlftを持つキャンペーンに属するリードが必要です。もし私が左のジョインでそれを行い、それをジョインに含めると、それらのキャンペーンの外にもリードが与えられます。正しい? – Leuven

+0

GROUP BYがほとんどの遅延を引き起こしているようです。それをグループ化せずに実行するにはスプリット秒がかかります。しかし、私は同じ数字を2回以上引いてはいけません。 – Leuven

+0

グループを削除し、別名を追加します。あなたは集約を使用していないし、私が最近読んだことのある記事は、mySQLにおいてDistinctはもっと速くなると言いました。実行計画/指標の評価は知る唯一の方法となるだろう。記事には適切なインデックスが記載されていますが、グループの方がパフォーマンスが優れているはずです。私は、あなたの望む結果にも欠点があることを心配していたので、左の結合とwhereの節で問題が生じました。 – xQbert

関連する問題