著者: 2000 年 1 月 24日にTom Lane (<tgl@sss.pgh.pa.us>) によって書かれました。
Note: これは最終的には、新しいインデックスアクセスメソッドの書き方についての もっと大きい章の一部にならなければいけません。
すべてのインデックスアクセスメソッドは、プランナ/オプティマイザから 使用できるようにコスト概算関数を提供しなければなりません。この関数の プロシージャ OID はアクセスメソッドのpg_am の フィールドamcostestimateで与えられます。
Note: Postgres 7.0 以前では、インデックスを指定したコスト概算関数の 登録には、違った方法が使われていました。
関数 amcostestimate は、インデックスと共に使えることが決定された WHERE 句のリストを与えられます。この関数はインデックスにアクセス するコストの概算と WHERE 句の選択度(これはインデックススキャンの間に 抽出されるメインテーブルのタプルの一部分です)を返さなくてはいけません。 単純な場合だと、ほとんどすべてのコスト概算の作業がオプティマイザの 標準ルーチンを呼び出すことでできます。amcostestimate 関数を持つことの 意味は、標準概算を改善することが可能な場合に、インデックスアクセスメソッド がインデックス型を指定した 知識を供給することを許可することです。
それぞれの amcostestimate 関数はシグニチャをもたなければいけません:
void amcostestimate (Query *root, RelOptInfo *rel, IndexOptInfo *index, List *indexQuals, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity);最初の4つのパラメータは引数です:
処理されている問い合わせ。
指定されたインデックスがあるリレーション。
インデックスそのもの。
インデックス制約句のリスト(暗黙には ANDed); NIL リストは使える制約がないことを表します。
最後の三つのパラメータは参照引渡しの返り値です。
インデックス開始プロセスのコストに設定されています。
インデックスプロセスの全体のコストに設定されています。
インデックスの選択度に設定されています。
コスト概算関数は、SQL やその他の手続言語ではなく、 C 言語で書かれなければ いけないことに注意して下さい。 これはプランナ/オプティマイザの内部データ構造にアクセスしなければならない ためです。
インデックスアクセスコストは src/backend/optimizer/path/costsize.c で使われるユニットで計算されるべきです。順番に並んだディスクブロック 取り出しは 1.0 のコストがかかっており、順不同の取り出しは random_page_cost のコストがかかっています。そして、一つのインデックスタプルの処理のコスト は通常 cpu_index_tuple_cost とされるべきです(これはユーザが調節可能な オプティマイザパラメータです)。更に、cpu_operator_cost が相応の 数に増えると、インデックス処理の間に呼び出される比較演算子も コストに加算されます(特にindexQuals 自身の評価では)。
アクセスコストは、インデックス自身のスキャンと関係する全てのディスクと CPU コストも含むべきですが、インデックスで指定されるメインテーブルの タプルの処理や抽出は含みません。
"開始コスト" は、最初のタプルの取り出しを始める前に使い果たされなければ ならない総計スキャンコストの一部です。ほとんどのインデックスでは これはゼロとされますが、高い開始コストを持つインデックス型ではゼロ以外 に設定した方が良いかもしれません。
indexSelectivity は、インデックススキャンの間に抽出されるメインテーブルの タプルの概算された一部分として設定されるべきです。浪費の多いインデックス の場合はこの値が、与えられた制約条件を実際に通過するタプルの部分 よりも高くなることがよくあります。
コスト概算
典型的なコスト概算は次のように進められます:
与えられた制約条件に基づいて訪れられるメインテーブルのタプルの一部分を 概算して返します。インデックス型を指定した知識がない場合、標準 のオプティマイザ関数である clauselist_selectivity() を使って下さい。
*indexSelectivity = clauselist_selectivity(root, indexQuals, lfirsti(rel->relids));
スキャン中に訪れられるインデックスタプルの数を概算します。多くの インデックス型にとって、これは indexSelectivity とインデックスの中 にあるタプルの数を掛けたものと等しいですが、それより多い場合もあります。 (インデックスのページ数とタプルは IndexOptInfo 構文から得ることが できます。)
スキャン中に抽出されるインデックスページの数を概算します。 これは indexSelectivity とインデックスのページ数ちょうどでしょう。
インデックスアクセスコストを計算します。一般的な概算では このようなことをするでしょう:
/* ここでの全体的な憶測は、インデックスページが順番に読まれ、それぞれに * random_page_cost ではなく 1.0 のコストがかかるということです。 * さらに、それぞれのインデックスタプルの indexquals の評価も加算され * ます。すべてのコストはスキャンの間増加しながらかかっていくと * 仮定されます。 */ *indexStartupCost = 0; *indexTotalCost = numIndexPages + (cpu_index_tuple_cost + cost_qual_eval(indexQuals)) * numIndexTuples;
コスト概算関数の例は src/backend/utils/adt/selfuncs.c で見つけることができます。
通常は、amcostestimate関数のpg_proc 項目は下記のように表示されます。
prorettype = 0 pronargs = 7 proargtypes = 0 0 0 0 0 0 0pg_type で知られる型を持っている引数がないため、ここでは 0 (ゼロ)を 使っています。