MySQL5.6→5.7のアップデートで意図せぬスロークエリが発生した
何が起きていたのか
クエリのTypeがrange
からフルインデックススキャンに変化していた
原因
range_optimizer_max_mem_size
というパラメータが追加されていた
範囲オプティマイザで使用可能なメモリを制御するには、range_optimizer_max_mem_size システム変数を使用します。
・値0は、「制限なし」を意味します。
・0より大きい値を指定すると、オプティマイザは、範囲アクセス方法を検討する際に消費されるメモリを追跡します。指定された制限値を超えそうになると、範囲アクセス方法は放棄され、代わりにテーブルのフルスキャンを含む他の方法が検討されます。これは最適ではない可能性があります。このような場合、次のような警告が発生します(Nは現在のrange_optimizer_max_mem_sizeの値)。
Warning 3170 Memory capacity of N bytes for 'range_optimizer_max_mem_size' exceeded. Range optimization was not done for this query.
・UPDATEおよびDELETE文において、オプティマイザが完全なテーブルスキャンにフォールバックし、sql_safe_updatesシステム変数が有効になっている場合、事実上、どの行を変更するかを決定するためのキーが使用されないため、警告ではなくエラーが発生します。詳細は、セーフアップデートモードの使用(-saf-updates)を参照してください。使用可能な範囲最適化メモリーを超え、オプティマイザーが最適性の低いプランにフォールバックする個々のクエリのrange_optimizer_max_mem_size 場合、 値を増やすとパフォーマンスが向上する可能性があります。
スロークエリになっていた部分はIN句にて大量のIDを指定していたため、このオプティマイザの仕様にひっかかってしまったようです。
具体的な値に関しては以下の表のようになっています。
Command-Line Forma | --range-optimizer-max-mem-size=# |
System Variable | range_optimizer_max_mem_size |
Scope | Global, Session |
Dynamic | Yes |
Type | Integer |
Default Value (≥ 5.7.12) | 8388608 |
Default Value (≤ 5.7.11) | 1536000 |
Minimum Value | 0 |
Maximum Value | 18446744073709551615 |
IN句に指定するIDを減らしたところ見事解決しました。
参考
MySQL公式
Range Optimization
Server System Variables
バージョンアップに際して参考にした記事
本記事の内容とは関係なくアップデート時に参考にした記事です。
MySQL公式
What is new in MySQL5.7
SQL Mode Changes in MySQL 5.7
slideShare
MySQL 5.7にやられないためにおぼえておいてほしいこと
Discussion