9.3 9.4 9.5 9.6 10 11 12 13 14 Current(15)
阿里云PostgreSQL 问题报告 纠错本页面

55.1. 采样方法支持功能

TSM处理函数返回包含指向下面描述的支持函数的指针的palloc'd TsmRoutine结构。 大多数函数是必需的,但有些是可选的,这些指针可以为NULL。

void
SampleScanGetSampleSize (PlannerInfo *root,
                         RelOptInfo *baserel,
                         List *paramexprs,
                         BlockNumber *pages,
                         double *tuples);

在计划期间调用此函数。它必须估计在样本扫描期间将要读取的关系页的数量, 以及将由扫描选择的元组的数量。(例如,这些可以通过估计采样分数, 然后乘以baserel->pagesbaserel->tuples 数字来确定,确保将结果舍入为整数值。)paramexprs列表包含表达式, 它们是TABLESAMPLE子句的参数。建议使用estimate_expression_value() 尝试将这些表达式减少为常量,如果它们的值需要用于估计目的; 但是函数必须提供大小估计,即使它们不能被减少,并且它不应该失败,即使值看起来无效 (记住它们只是运行时值的估计)。pagestuples参数是输出。

void
InitSampleScan (SampleScanState *node,
                int eflags);

初始化以执行SampleScan计划节点。这在执行程序启动期间被调用。 它应该在处理可以开始之前执行任何所需的初始化。 SampleScanState节点已创建,但其tsm_state字段为NULL。 InitSampleScan函数可以palloc采样方法所需的任何内部状态数据, 并在node->tsm_state中存储指向它的指针。 有关要扫描的表的信息可以通过SampleScanState节点的其他字段访问 (但请注意,node->ss.ss_currentScanDesc扫描描述符尚未设置)。 eflags包含描述此计划节点的执行程序操作模式的标志位。

(eflags & EXEC_FLAG_EXPLAIN_ONLY)为true时, 实际上不会执行扫描,因此此函数应该只做使EXPLAINEndSampleScan的节点状态有效所需的最小值。

可以省略此函数(将指针设置为NULL),在这种情况下, BeginSampleScan必须执行抽样方法所需的所有初始化。

void
BeginSampleScan (SampleScanState *node,
                 Datum *params,
                 int nparams,
                 uint32 seed);

开始执行采样扫描。这在第一次尝试获取元组之前被调用,并且如果需要重新启动扫描, 则可以再次调用。有关要扫描的表的信息可通过SampleScanState 节点的字段访问(但请注意,node->ss.ss_currentScanDesc扫描描述符尚未设置)。 params数组的长度为nparams,包含TABLESAMPLE 子句中提供的参数的值。这些将具有采样方法的parameterTypes 列表中指定的数字和类型,并且已被选中不为null。seed 包含用于在采样方法内生成的任何随机数的种子;它是从REPEATABLE 值派生的散列(如果给出了一个),或者是random()的结果,如果没有。

此函数可以调整字段node->use_bulkreadnode->use_pagemode。 如果node->use_bulkreadtrue(这是缺省), 扫描将使用一个缓冲区访问策略,鼓励在使用后回收缓冲区。 如果扫描只访问表的一小部分页面,那么将其设置为false可能是合理的。 如果node->use_pagemodetrue(这是缺省), 则扫描将对每个访问页面上的所有元组单次执行可见性检查。 如果扫描只在每个访问页面上选择元组的一小部分, 则将此值设置为false可能是合理的。 这将导致执行更少的元组可见性检查,虽然每个将更昂贵,因为它将需要更多的锁定。

如果采样方法标记为repeatable_across_scans, 它必须能够在重新扫描期间选择与原来相同的元组集合, 即对BeginSampleScan的新调用必须导致选择与以前相同的元组 (如果TABLESAMPLE参数和种子没有改变)。

BlockNumber
NextSampleBlock (SampleScanState *node);

返回要扫描的下一页的块编号,如果没有剩余要扫描的页, 则返回InvalidBlockNumber

此函数可以省略(将指针设置为NULL),在这种情况下, 核心代码将执行整个关系的顺序扫描。这样的扫描可以使用同步扫描, 使得采样方法不能假定在每次扫描时以相同的顺序访问关系页面。

OffsetNumber
NextSampleTuple (SampleScanState *node,
                 BlockNumber blockno,
                 OffsetNumber maxoffset);

返回指定页面上要采样的下一个元组的偏移号,如果没有元组仍然要采样, 则返回InvalidOffsetNumbermaxoffset是页面上使用的最大偏移量。

注意: NextSampleTuple没有明确告诉哪个偏移号在1 .. maxoffset 的范围内实际包含有效的元组。这通常不是问题, 因为核心代码忽略了采样缺失或不可见元组的请求;这不应导致样品中的任何偏差。 但是,如果需要,函数可以检查node->ss.ss_currentScanDesc->rs_vistuples[] 以标识哪些元组是有效的和可见的。(这需要node->use_pagemodetrue。)

注意: NextSampleTuple不能假定blockno 是由最近的NextSampleBlock调用返回的相同的页码。 它是由一些先前的NextSampleBlock调用返回的, 但是核心代码允许在实际扫描页面之前调用NextSampleBlock, 以便支持预取。可以假定一旦给定页面的采样开始, 连续的NextSampleTuple调用都引用相同的页面, 直到返回InvalidOffsetNumber

void
EndSampleScan (SampleScanState *node);

结束扫描并释放资源。通常,释放palloc'd内存并不重要, 但是任何外部可见的资源都应该清除。在没有此类资源的常见情况下, 可以省略此函数(将指针设置为NULL)。

<
/BODY >