【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 を指定してはいますが、とても遅い。
そんなものですか?
答え
この手の条件は、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: 全件」となります。
コメント