<p>customers (3000 行) とphone_call_log (350,000 行) の 2 つのテーブルがあります。 </p>
<p>通話ログを使用して各顧客への最後の通話時刻を実装する必要があります (フロントエンド検索の方が高速です)。 </p>
<p>インデックスは次のとおりです。</p>
<li>start_time (タイムスタンプ)</li>
<li>call(bigint(32) unsigned)</li>
<li>Caller(bigint(32) unsigned)</li>
<li>電話番号 (bigint(32) unsigned)</li>
<li>last_call(タイムスタンプ)</li>
</ul>
<p>このクエリを実行すると、呼び出し元/呼び出し先の列の完了時間は OR ステートメントを使用しない場合は 2 秒未満ですが、OR ステートメントを使用すると完了しません (テストでは、実行させませんでした) 30分以上)。 </p>
<pre class="brush:sql;toolbar:false;">顧客を更新する
SET Customers.last_call = (
SELECT max(phone_call_log.start_time)
電話の通話記録から
WHERE Phone_call_log.callee = 顧客.電話番号
または、phone_call_log.caller = 顧客.電話番号
)
WHERE 顧客.電話番号が NULL ではない
AND 長さ(顧客.電話番号) > 6
かつ顧客の電話番号 > 1000000;
</pre></p>
最速
電話がかかってきたら、データ フローを変更して
customers.last_call
を更新します。接続の更新
######または######UPDATE
JOIN
と比較すると、IN (SELECT ...)
の方が効果的です。OR はパフォーマンスを低下させます。このクエリでは、各顧客の
phone_call_log全体をスキャンする可能性が高くなります。
回避策の 1 つは、
リーリーUPDATE
を 2 回実行し、適切なインデックスを使用することです:これには、
リーリーphone_call_log
に次のインデックスを作成する必要があります:And
現在の単一列インデックスの呼び出し元と呼び出し先を削除します。データの種類
電話番号の場合、特に LENGTH(customers.phonenumber) > 6 を考慮すると、
BIGINTの使用は間違っている可能性があります。
実際には、これらすべては簡単なテストに要約されます:
>リーリー
すべてのチェックでは
NOT NULLがチェックされ、データ型に応じてそのうちの 1 つだけが使用され、インデックスが付けられます。
(
SHOW CREATE TABLE
を入力してください。「英語」では正確さが不十分です。)
リーリーOR
を使用したクエリでは、インデックスを効果的に使用できません。次のことを試してみることをお勧めします:#GREATEST
には NULL 値の処理に問題があることに注意してください。