前置き
SQLの実行する前に、「どのようにプロセスが実行され、どのようを改善したら素早いクエリが実行できるのか?を図形的に捉えることは重要なことです。
策もなしに、SQLを雑に描いていては、素早く実行できるものも、遅くなってしまいます。
そこで今回は、ECRS原則を用いた、SQLチューニングについて触れていきます。
ECRSについて簡単におさらい
この原則については、過去にいろいろ記事を書いてるのでそちらを参考にしてください。
ECRS原則は、もともと製造業の業務改善(カイゼン)で使われる考え方ですが、SQLのクエリチューニングに応用するのは、非常に的確で効果的なアプローチです。
JOIN句は、テーブルのデータを一度メモリ上に展開し、結合条件に基づいてレコードを照合するという、本質的にコストの高い操作です。
そのため、ボトルネックに割かしなりやすい部分ではあります。
ECRSのフレームワークは、このコストの高いJOIN操作を、体系的に見直すための優れた思考ツールとなります。
Eliminate (なくせないか? - 排除)
「そもそも、このJOINは本当に必要か?」
を問います。JOIN句自体をなくせれば、効果は絶大です。
非正規化
最も強力な手法です。
ordersテーブルを検索する際に、顧客名を表示するために毎回customersテーブルをJOINしているのであれば、あらかじめordersテーブルにcustomer_nameカラムを追加・保存しておくことで、JOINそのものを排除します。
ただし、データの冗長性とのトレードオフになる。
これにより、読み取り時のJOINは不要になりますが、代わりに書き込み(INSERT/UPDATE)時に、以下のように両方のデータを同期させる余分な処理が必要になります。
※データの不整合リスクが上がるので、私はほぼこの手法は好みません。
不要なJOINの削除
クエリをコピー&ペーストするうちに、SELECT句では使われていないのに、JOIN句だけが残っているケースがあります。
このような不要なJOINは、単純に削除します。
Combine (一緒にできないか? - 結合)
「複数の処理を、より少ない処理にまとめられないか?」
を問います。
クエリの統合
アプリケーションが、ループ内で何度も個別のクエリを発行しているのであれば、それらをUNION ALLやCASE文を使って、単一のクエリにまとめることで、データベースへのラウンドトリップ(往復回数)を減らします。
マテリアライズド・ビュー(実体化ビュー)
頻繁にJOINされるテーブル群を、あらかじめJOINした結果として、物理的なテーブル(マテリアライズド・ビュー)として保持しておきます。
クエリは、この事前に結合済みの単一テーブルを参照するだけで済みます。
詳細
特に分析系のクエリで、毎回同じ複雑なJOINや集計を繰り返している場合に有効です。
その重いクエリの結果を、あらかじめ物理的な実体を持つマテリアライズド・ビューとして保存しておく。
すると利用者は、その軽量な結果テーブルを叩くだけで済むようになります。
※トレードオフは、データの鮮度です。
ビューは定期的にリフレッシュする必要があり、リアルタイムのデータは反映されません。
具体例
日次の売上集計レポートのために、毎回重い集計クエリを実行している場合。
Rearrange (順序を変えられないか? - 交換)
「処理の順序を入れ替えて、効率化できないか?」
を問います。
先にフィルタ、後でJOIN
巨大なテーブル同士をJOINする前に、WHERE句やサブクエリ、CTE(共通テーブル式) を使って、各テーブルをできるだけ小さなサイズに絞り込んでからJOINします。
これにより、JOINが処理すべきレコード数が劇的に減り、パフォーマンスが向上します。
詳細
巨大なテーブル同士をJOINする場合、
JOINする前にWHERE句で可能な限りレコードを絞り込む
ことが鉄則です。
これにより、JOINアルゴリズムが処理しなければならないデータ量が劇的に減ります。
現代の多くのクエリオプティマイザは自動でこれを行いますが、サブクエリやCTE(共通テーブル式)を使って明示的に順序を指示することで、より確実な性能向上が期待できます。
具体例
東京都の顧客の注文履歴を検索する場合。
Simplify (もっと単純にできないか? - 単純化)
「処理をもっとシンプルな方法で実現できないか?」
を問います。
上記のEやCが実行できそうにない時には、ココから始めてしまっても何ら問題ないです。
インデックスの活用
JOINするカラムや、WHERE句で頻繁に使うカラムに適切なインデックスを作成します。
これにより、テーブルのフルスキャンという最も重い処理が、高速なインデックス検索に置き換わります。
WHERE句の関数使用を避ける
WHERE YEAR(order_date) = 2025
のような書き方は、order_dateのインデックスが使えなくなる原因です。
WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01'
のように、インデックスが有効になるシンプルな比較に書き換えます。
具体例
顧客コードの先頭2文字が'TK'の顧客を探すような場合。
存在確認にはEXISTSを使う
「テーブルAに存在するレコードのうち、テーブルBにも対応するレコードが存在するもの」を取得したい場合、JOINやIN句よりもWHERE EXISTS (...)を使った方が、高速になることがあります。
まとめ
このように、ECRSの原則を適用することで、場当たり的ではない、体系的なクエリの改善・リファクタリングが可能になります。
是非、いきなりSQL書くんでなく、一旦立ち止まり、モデルを描いて、ECRSを適用してみてから、コードを書いてみてください。