データベースのクエリを固定ルールで書き換えて高速化する、古典的なクエリ最適化手法
ルールベース最適化(Rule-Based Optimization, RBO)は、データベースのクエリを高速に実行できる形に書き換える手法の一つです。 初期のデータベース製品(Oracle v7以前、初期のMySQL)で主に採用されていました。現在はコストベース最適化(CBO)が主流ですが、RBOの概念は今でもCBOの中に部品として残っています。
RBOの最大の特徴は、テーブルの統計情報(行数、カーディナリティなど)を一切使わないことです。 代わりに「Selection Pushdownは常に良い」「Projection Pushdownは常に良い」といった固定のルール(書き換え規則)を優先度順に機械的に適用します。
中でも最も重要なルールはSelection Pushdown(選択プッシュダウン)です。 これはWHERE条件をクエリツリーの下の方(データソースに近い側)に移動させることで、JOINなどの重い処理に渡す行数を早い段階で削減する手法です。 例えば100万行のテーブル同士をJOINした後にWHEREで絞るのではなく、先にWHEREで1000行に絞ってからJOINすれば、処理量は劇的に減ります。
上のビジュアライザーに表示されているツリーは、SQLクエリの実行計画(クエリツリー)を表しています。 各ノードはクエリの中の一つの処理ステップに対応します。
料理のレシピを効率化するイメージです。レシピに「野菜を全部洗って、全部切って、必要なものだけ選んで料理する」と書いてあったら、「必要なものだけ先に選んでから洗って切る」方が効率的ですよね? ルールベース最適化はこのような「明らかに効率的な書き換え」をルールとして持っています。
WHERE条件をツリーの下に移動し、不要な行をJOINの前に除外します。100万行をJOINしてから絞るのではなく、先に1000行に絞ってからJOINします。
不要なカラムをできるだけ早い段階で捨てます。10カラムあっても使うのが2カラムなら、最初から2カラムだけ持ち運びます。
WHERE price > 50 + 50 のような定数式を、実行前に WHERE price > 100 に変換します。実行時に毎回計算する無駄を省きます。
ルールベースは「こうしたら必ず速くなる」という確実なルールだけを適用するため、テーブルの大きさを知らなくても使えます。ただし、テーブルの大きさによって最適解が変わるケース(seq_scan vs index_scan)には対応できません。そのような判断には、統計情報を使うコストベース最適化(CBO)が必要になります。
| 観点 | Rule-Based (RBO) | Cost-Based (CBO) |
|---|---|---|
| 判断基準 | 固定ルール(優先度順) | コストモデル(I/O, CPU, メモリ推定値) |
| 統計情報 | 使わない | テーブル行数、カーディナリティ、ヒストグラムなどを使用 |
| 結果の予測性 | 常に同じ結果(決定論的) | 統計が変わると実行計画が変わりうる |
| 最適性 | データ分布を考慮できず、最適とは限らない | より正確にコストを推定し、最適に近い計画を選択 |
| 実装コスト | シンプル・軽量 | 統計収集・コストモデル・探索空間の管理が必要 |
| 代表的なDB | Oracle v7以前、MySQL 3.x、SQLite | Oracle 7+、PostgreSQL、MySQL 5.x+、SQL Server |
| 現在の位置づけ | CBOのヒューリスティック段階として残存 | 主流。ほぼすべての商用・OSSのRDBMSが採用 |
現代のデータベースでは、CBOが主流です。しかしCBOの内部でも、明らかに有利な変換(Selection PushdownやConstant Foldingなど)は ヒューリスティック段階としてRBOのルールが先に適用されます。RBOを学ぶことは、CBOの理解にも直結します。