# 62.6.指数成本估算函数

这个成本估算函数提供了描述可能的索引扫描的信息,包括已确定可用于索引的WHERE和ORDER BY子句的列表。它必须返回访问索引的成本估计值和WHERE子句的选择性(即在索引扫描期间将检索到的父表行的分数)。对于简单的情况,成本估算器的几乎所有工作都可以通过调用优化器中的标准例程来完成;拥有一个成本估算功能是允许索引访问方法提供索引类型特定的知识,以防有可能改进标准估计。

每个成本估算函数必须具有以下签名:

void
amcostestimate (PlannerInfo *root,
                IndexPath *path,
                double loop_count,
                Cost *indexStartupCost,
                Cost *indexTotalCost,
                Selectivity *indexSelectivity,
                double *indexCorrelation,
                double *indexPages);

前三个参数是输入:

规划师关于正在处理的查询的信息。

路径

正在考虑的索引访问路径。除成本和选择性值外的所有字段均有效。

循环计数

成本估算中应考虑的索引扫描重复次数。当考虑在nestloop联接内部使用参数化扫描时,这通常会大于1.请注意,成本估算仍应仅用于一次扫描;更大的*循环计数*这意味着允许在多个扫描中产生一些缓存效果可能是合适的。

最后五个参数是通过参考输出:

*`*indexStartupCost`*

设置为索引启动处理的成本

*`*指数成本`*

设置为索引处理的总成本

*`*指数选择性`*

设置为索引选择性

*`*指数相关性`*

设置为索引扫描顺序和基础表顺序之间的相关系数

*`*指数膨胀`*

设置为索引叶页数

请注意,成本估算函数必须用C语言编写,而不是SQL或任何可用的过程语言,因为它们必须访问planner/optimizer的内部数据结构。

索引访问成本应使用src/backend/optimizer/path/costsize。C:顺序磁盘块取数需要成本seq_page_成本,一次不连续的取数是有代价的随机页面成本,处理一个索引行的成本通常应视为cpu索引元组成本.此外,适当的cpu_操作员_成本应为索引处理期间调用的任何比较运算符(尤其是对indexquals本身的评估)收取费用。

访问成本应包括与扫描索引本身相关的所有磁盘和CPU成本,但检索或处理由索引标识的父表行的成本。

“启动成本”是在开始获取第一行之前必须花费的总扫描成本的一部分。对于大多数索引,这可以被视为零,但启动成本高的索引类型可能希望将其设置为非零。

这个*指数选择性*应设置为索引扫描期间将检索的父表行的估计分数。在有损查询的情况下,这通常会高于实际通过给定qual条件的行的分数。

这个*指数相关性*应设置为索引顺序和表顺序之间的相关性(介于-1.0和1.0之间)。这用于调整从父表获取行的成本估算。

这个*指数膨胀*应设置为叶页数。这用于估计并行索引扫描的工作人员数量。

什么时候*循环计数*大于1时,返回的数字应为索引任何一次扫描的预期平均值。

成本估算

典型的成本估算师将按照以下步骤进行:

  1. 根据给定的qual条件估计并返回将被访问的父表行的比例。在没有任何索引类型特定知识的情况下,使用标准优化器函数从句学家:

    *indexSelectivity = clauselist_selectivity(root, path->indexquals,
                                               path->indexinfo->rel->relid,
                                               JOIN_INNER, NULL);
    
  2. 估计扫描期间将访问的索引行数。对于许多索引类型,这与*指数选择性*乘以索引中的行数,但可能更多。(请注意,可以从路径->索引信息结构。)

  3. 估计扫描期间将检索的索引页数。这可能只是*指数选择性*乘以索引的大小(以页为单位)。

  4. 计算索引访问成本。一般估计器可能会这样做:

    /*
     * Our generic assumption is that the index pages will be read
     * sequentially, so they cost seq_page_cost 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, path->indexquals, root);
    *indexStartupCost = index_qual_cost.startup;
    *indexTotalCost = seq_page_cost * numIndexPages +
        (cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
    

    然而,以上并没有考虑重复索引扫描中索引读取的摊销。

  5. 估计指数相关性。对于单个字段上的简单有序索引,可以从pg中检索_统计资料如果相关性未知,保守估计为零(无相关性)。

    有关成本估算函数的示例,请参见src/backend/utils/adt/selfuncs。C.