はじめに
この記事は「 実行計画キャッシュ の再利用 多段階JOINを含むSQL」シリーズの後編です。前編では5段階JOINと複数集計を含むクエリを対象にしたテーブル設計とデータ投入を、そして中編では4つの異なるクエリ構文パターン(リテラル固定、リテラル可変、PREPARE固定、SET + PREPARE)におけるEXPLAIN ANALYZEの出力を比較しました。
後編となる本記事では、それぞれのクエリを1000回ずつ実行した際のパフォーマンスデータを元に、実行計画キャッシュの再利用や構文の違いによる実行速度への影響を検証・考察します。MySQLは8.4.5を利用しています。
パターンごとの1000回実行結果
各パターンを1000回ずつ実行し、平均実行時間・合計実行時間を測定しました。結果は以下の通りです。
パターン | 内容 | total_time_sec | avg_time_sec |
---|---|---|---|
1 | リテラル固定(user_id = 1234 ) |
599.4615 秒 | 0.5995 秒 |
2 | リテラル可変(user_id = [変更あり] ) |
598.7534 秒 | 0.5988 秒 |
3 | PREPARE + EXECUTE (user_id固定) |
615.8934 秒 | 0.6159 秒 |
4 | SET @user_id + PREPARE + EXECUTE (変更)※SET含む |
615.7727 秒 | 0.6158 秒 |
実行結果の比較と解釈
パターン1が他よりも速かった理由
リテラル固定はキャッシュの再利用が難しいとされますが、今回の測定では結果的に最も高速でした。MySQLのパーサやオプティマイザが十分に効率化されている可能性があります。単純な構文であるがゆえにオーバーヘッドが最小限に抑えられているのかもしれません。
パターン2もほぼ同等の速さ
user_idを変更しても構文の大枠が変わらないため、MySQLの内部で解析や最適化が効率化されている可能性はあります。ただし、今回の検証ではステートメントキャッシュの明確な影響は確認できておらず、「キャッシュが効いている」と断言する根拠はありません。
PREPARE系がやや遅い理由
パターン3とパターン4はやや遅くなっています。これはPREPARE + EXECUTEの構造がストアド・ステートメント的な扱いとなり、毎回の EXECUTE
呼び出しのたびに多少の内部処理コストが発生するためと考えられます。また、今回の計測結果ではリテラル構文とPREPARE構文の間に約2〜3%の差が見られました。SQLインジェクション対策としてPREPAREを採用することは正当であり、セキュリティの代償としてこの程度のパフォーマンス差は許容範囲と考えるべきです。
SET変数のオーバーヘッドについて
パターン4ではSETを1000回実行しており、その合計時間が0.1320秒
と画像から確認できました。つまり、SET文1回あたりの平均は0.0001秒程度であり、今回の合計実行時間に大きな影響は与えていません。SETのオーバーヘッドは無視できるほど小さいと考えてよいでしょう。
MySQL まとめ
- リテラル固定でもパフォーマンスは高かった(キャッシュ以外の要因の可能性)
- PREPARE構文は安全で再利用性が高いが、やや遅延が見られることもある
- SET変数のオーバーヘッドは非常に小さい(0.132秒/1000回)
- 今回の検証でもステートメントキャッシュの影響は明確に確認できなかった
- リテラル構文とPREPARE構文では約2%の実行時間差があり、これはセキュリティ対策のコストとして妥当な範囲
次回のテーマ
SQLインジェクション
コメントを残す