🚴‍♀️

MySQL5.6→5.7のアップデートで意図せぬスロークエリが発生した

2021/11/09に公開

何が起きていたのか

クエリの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