pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
由 Tom Lane(<tgl@sss.pgh.pa.us>)于 2000-01-24 撰写
这些内容最终应成为关于编写新索引访问方法的更大章节的一部分。
每种索引访问方法都必须提供一个供规划器/优化器使用的代价估计函数。该函数的过程 OID 记录在访问方法的 pg_am 项的 amcostestimate 字段中。
在 PostgreSQL 7.0 之前,注册索引特定的代价估计函数使用的是另一种方案。
amcostestimate 函数会得到一个已判定可用于该索引的 WHERE 子句列表。它必须返回访问索引的代价估计以及 WHERE 子句的选择率估计(即在索引扫描期间将被检索的主表行所占的比例)。对于简单情况,代价估计器几乎全部工作都可以通过调用优化器中的标准例程完成;设置 amcostestimate 函数的意义在于让索引访问方法提供索引类型特定的知识,以便在可能改进标准估计时加以利用。
每个 amcostestimate 函数必须具有如下签名:
void
amcostestimate (Query *root,
RelOptInfo *rel,
IndexOptInfo *index,
List *indexQuals,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
前四个参数是输入:
正在处理的查询。
索引所在的关系。
索引本身。
索引限定条件子句的列表(隐含 AND 连接);NIL 列表表示没有可用的限定条件。
后四个参数是按引用传递的输出:
设置为索引启动处理的代价
设置为索引处理的总代价
设置为索引选择率
设置为索引扫描顺序与底层表顺序之间的相关系数
注意,代价估计函数必须用 C 编写,而不能用 SQL 或任何可用的过程语言,因为它们必须访问规划器/优化器的内部数据结构。
索引访问代价应按 src/backend/optimizer/path/costsize.c 所用的单位计算:顺序磁盘块读取的代价为 1.0,非顺序读取的代价为 random_page_cost,而处理一个索引行的代价通常取为 cpu_index_tuple_cost(这是一个用户可调的优化器参数)。此外,对于索引处理期间调用的任何比较操作符(尤其是 indexQuals 本身的求值),应收取适当的 cpu_operator_cost 倍数。
访问代价应包括扫描索引本身相关的所有磁盘和 CPU 代价,但不包括检索或处理由该索引标识的主表行的代价。
“启动代价”是总扫描代价中在可以开始取第一行之前必须付出的部分。对大多数索引来说可以取零,但启动代价很高的索引类型可能希望把它设为非零。
indexSelectivity 应设置为索引扫描期间将检索的主表行的估计比例。对于有损索引,这通常会高于实际满足给定限定条件的行所占的比例。
indexCorrelation 应设置为索引顺序与表顺序之间的相关性(取值范围在 -1.0 到 1.0 之间)。它用于调整从主表取行的代价估计。
代价估计
典型的代价估计器按如下步骤进行:
基于给定的限定条件,估计并返回将被访问的主表行所占的比例。在没有索引类型特定知识的情况下,使用标准优化器函数 clauselist_selectivity():
*indexSelectivity = clauselist_selectivity(root, indexQuals,
rel->relid, JOIN_INNER);
估计扫描期间将访问的索引行数。对许多索引类型来说,它等于 indexSelectivity 乘以索引中的行数,但也可能更多。(注意,索引的页数和行数可以从 IndexOptInfo 结构中获得。)
估计扫描期间将检索的索引页数。它可以就是 indexSelectivity 乘以索引的页数。
计算索引访问代价。一个通用估计器可以这样做:
/*
* Our generic assumption is that the index pages will be read
* sequentially, so they have cost 1.0 each, not random_page_cost.
* Also, we charge for evaluation of the indexquals at each index row.
* All the costs are assumed to be paid incrementally during the scan.
*/
cost_qual_eval(&index_qual_cost, indexQuals);
*indexStartupCost = index_qual_cost.startup;
*indexTotalCost = numIndexPages +
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
估计索引相关性。对于单字段上的简单有序索引,可以从 pg_statistic 中取得相关性。如果相关性未知,保守的估计是零(无相关)。
代价估计器函数的例子可以在 src/backend/utils/adt/selfuncs.c中找到。
按照惯例,amcostestimate函数的 pg_proc 项应显示八个全声明为 internal 的参数(因为它们都没有 SQL 已知的类型),而返回类型为 void。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。