SOFTELメモ

Softel Inc.

【MySQL】WHERE句にORを大量につなげると遅くなることがある

問題

複合キーのテーブルで、以下のようなSQLがものすごい時間をかけているのを見かけました。

UPDATE xxxx
SET xxx_flag = 1
WHERE (order_no = '20180921-00123704' AND row_no = '2')
OR (order_no = '20180922-00102730' AND row_no = '3')
OR (order_no = '20190423-00152822' AND row_no = '1')
OR …
OR …
OR … 以下2,3万行続く

order_no と row_no で primary key を指定してはいますが、とても遅い。

そんなものですか?

mysql

答え

この手の条件は、ORの件数によって実行計画が変わるようです。

ある200万行あるテーブルの場合、
条件が1個ならprimary key 使用。
ORが2個、3個でもインデックス使用。
ORを5000個並べた場合はインデックス使用。
ORを6000個並べた場合はインデックス使用。
ORを8000個並べたら全件スキャン(このあたりから急激に遅くなる)。
ORを10000個並べたら全件スキャン。
といった結果になりました。

OR に並べる件数もほどほどがよいようです。

今回のUPDATE文なら、3万個を5000個ずつに分けて実行すると速くなるでしょう。

「ほどほど」の基準はMySQLが決めていると思うので、一概には何とも言えない気がします。全体のレコード件数などによって変わりそうです。

MySQL5.6.3からは、更新系のSQL(UPDATE、INSERT, DELETE, REPLACE)でもEXPLAINが使用可能。それ以前のMySQLなら、SELECT文に書き換えてEXPLAINしてみると確認できます。

EXPLAIN すると、
ORが少ないうちは、「type: range、row: ORの件数分」ですが、
ORが多くなると、「type: ALL、row: 全件」となります。

関連するメモ

コメント