かみぽわーる

kamipo's blog

MySQLのクエリの良し悪しはrows_examinedで判断する

仕事やらなんやらでMySQLのクエリの良し悪しを判断する必要があるとき、EXPLAINの内容だけだとどのぐらい良くなったり悪くなったのか分からないので SET long_query_time = 0; してrows_examined (そのクエリでrows_sent行の結果を返すために何行に触ったのか)も一緒に提示するようにしている(少なくともMySQL 5.7時点ではrows_examinedはslow_query_logでしか確認できないはずperformance_schemaが有効ならevents_statements_historyやその仲間たちで確認できるとのこと*1 MySQL :: MySQL 5.6 リファレンスマニュアル :: 22.9.6 パフォーマンススキーマステートメントイベントテーブル)。

例:

f:id:kamipo:20180322074906p:plain

上の例のBeforeは、もともとDBAが書いた温かみのあるSQLでORDER BY LIMIT最適化を効かせてLIMIT 20されたクエリをORDER BY狙いのインデックスを狙って20行の結果を返すために20行だけに触れている、つまり最も良い実行計画のクエリが、Afterでは深遠な理由により別のテーブルの条件で絞り込んだりしたりしなかったりするためのJOINで最適化の狙いが効かなくなって同じ20行の結果を返すために259454行に触れてしまうようになってしまったの図です。

f:id:kamipo:20180322074925p:plain

仕様を保ったまま最適化の狙いが効くようにクエリの書き変えを行うと、20行の結果を返すために駆動表と内部表それぞれ20行ずつだけ触るのが最も良い実行計画になるので、その修正案をrows_examinedと共に提示しているのが上の図です。

ゴルフで例えると、EXPLAINは大まかな方向性や飛距離を合わせるドライバーのような感じで、グリーンによせたあとカップを狙うパター的なのがrows_examinedという感じ。ドライバーでもパッティングできるけどパターも使いこなせるとスコアアップ間違い無し💪