データベースの実行計画のマニュアルや解説で下記の図のようなコストという概念が出て来る。私はデータベースの実行計画を勉強し始めたころ、このコストの概念が理解できずにもやもやして理解が進まなった。直観的には”コスト=処理時間”と思ってしまうがそうではない。整理しておきたいと思う。
コストの目的
データベースのオプティマイザが実行計画を決定するために使うものである。我々、技術者としては、オプティマイザがどのようにコストを考えたのか理解するために使う。
オプティマイザはハードウェアの相対的なコスト単価を定義しておき、処理内容からコスト合計を積み上げる。
コストの使い方(概要)
オプティマイザは複数の実行計画を作成し、その中からコストが小さいものを採用する。本質を理解するために非常にシンプルなケースを考えたい。
下記の場合は当然、実行計画2が選択される。我々、技術者はCPUもIOもフルスキャンした方がコスト大と判断されたことがわかる。
実行計画1 フルスキャン:CPUコスト100、IOコスト100、合計110
実行計画2 インデックスアクセス:CPUコスト10、IOコスト10、合計20
コストの使い方(詳細)
例えば、ストレージのランダムIO一回のコストを1とする。以下のようなコストについて相対的なコスト値を定義しておく。
ストレージ:シーケンシャルIO、CPUコスト:Where句のオペレーション、CPUコスト:データ取り出し、CPUコスト:関数
例えばランダムIO1回が5msecだとすると5msecのコストを1として、上記のそれぞれのコストを計測すれば、相対値を定義できる。データベース製品によるが多くの製品はデータベースが計測処理を実行して統計情報としてシステムテーブルにコスト値を保存している。
実際のデータベースでのコストの例
下記はPostgresqlのマニュアルからの抜粋である。(私の手元の数年前のメモなので変わっているかもしれないがここでは正確性は重要ではないのでそのまま使った。)
- シーケンシャルスキャン時のブロック読み込みコスト 1.0
- ランダムアクセス時のブロック読み込みコスト 4.0
- 1行を読み込むCPUコスト 0.01
- インデックス1エントリを読み込むCPUコスト 0.0025
以下の記事でハードウェアごとの処理時間の規模感をまとめている。ハードウェアの進化にも依存するため相違はあるが極端な違いはないと思う。
参考(Postgresqlのマニュアルから抜粋)
https://www.postgresql.jp/document/10/html/runtime-config-query.html
cpu_tuple_cost (floating point)
問い合わせ時のそれぞれの行の処理コストに対するプランナの推測を設定します。 デフォルトは0.01です。
cpu_index_tuple_cost (floating point)
インデックス走査時のそれぞれのインデックス行の処理コストに対するプランナの推測を設定します。 デフォルトは0.005です。
cpu_operator_cost (floating point)
問い合わせ時に実行される各演算子や関数の処理コストに対するプランナの推測を設定します。デフォルトは0.0025です。