PostgreSQL 9.5.3 中文手册 | |||
---|---|---|---|
上一页 | 上一级 | 章 55. 编写表采样方法 | 下一页 |
TSM处理函数返回包含指向下面描述的支持函数的指针的palloc'd TsmRoutine结构。 大多数函数是必需的,但有些是可选的,这些指针可以为NULL。
void SampleScanGetSampleSize (PlannerInfo *root, RelOptInfo *baserel, List *paramexprs, BlockNumber *pages, double *tuples);
在计划期间调用此函数。它必须估计在样本扫描期间将要读取的关系页的数量,
以及将由扫描选择的元组的数量。(例如,这些可以通过估计采样分数,
然后乘以baserel->pages和baserel->tuples
数字来确定,确保将结果舍入为整数值。)paramexprs列表包含表达式,
它们是TABLESAMPLE子句的参数。建议使用estimate_expression_value()
尝试将这些表达式减少为常量,如果它们的值需要用于估计目的;
但是函数必须提供大小估计,即使它们不能被减少,并且它不应该失败,即使值看起来无效
(记住它们只是运行时值的估计)。pages和tuples参数是输出。
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时,
实际上不会执行扫描,因此此函数应该只做使EXPLAIN
和EndSampleScan
的节点状态有效所需的最小值。
可以省略此函数(将指针设置为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_bulkread和node->use_pagemode。 如果node->use_bulkread为true(这是缺省), 扫描将使用一个缓冲区访问策略,鼓励在使用后回收缓冲区。 如果扫描只访问表的一小部分页面,那么将其设置为false可能是合理的。 如果node->use_pagemode为true(这是缺省), 则扫描将对每个访问页面上的所有元组单次执行可见性检查。 如果扫描只在每个访问页面上选择元组的一小部分, 则将此值设置为false可能是合理的。 这将导致执行更少的元组可见性检查,虽然每个将更昂贵,因为它将需要更多的锁定。
如果采样方法标记为repeatable_across_scans,
它必须能够在重新扫描期间选择与原来相同的元组集合,
即对BeginSampleScan
的新调用必须导致选择与以前相同的元组
(如果TABLESAMPLE参数和种子没有改变)。
BlockNumber NextSampleBlock (SampleScanState *node);
返回要扫描的下一页的块编号,如果没有剩余要扫描的页, 则返回InvalidBlockNumber。
此函数可以省略(将指针设置为NULL),在这种情况下, 核心代码将执行整个关系的顺序扫描。这样的扫描可以使用同步扫描, 使得采样方法不能假定在每次扫描时以相同的顺序访问关系页面。
OffsetNumber NextSampleTuple (SampleScanState *node, BlockNumber blockno, OffsetNumber maxoffset);
返回指定页面上要采样的下一个元组的偏移号,如果没有元组仍然要采样, 则返回InvalidOffsetNumber。maxoffset是页面上使用的最大偏移量。
注意:
NextSampleTuple
没有明确告诉哪个偏移号在1 .. maxoffset 的范围内实际包含有效的元组。这通常不是问题, 因为核心代码忽略了采样缺失或不可见元组的请求;这不应导致样品中的任何偏差。 但是,如果需要,函数可以检查node->ss.ss_currentScanDesc->rs_vistuples[] 以标识哪些元组是有效的和可见的。(这需要node->use_pagemode 为true。)
注意:
NextSampleTuple
不能假定blockno 是由最近的NextSampleBlock
调用返回的相同的页码。 它是由一些先前的NextSampleBlock
调用返回的, 但是核心代码允许在实际扫描页面之前调用NextSampleBlock
, 以便支持预取。可以假定一旦给定页面的采样开始, 连续的NextSampleTuple
调用都引用相同的页面, 直到返回InvalidOffsetNumber。
void EndSampleScan (SampleScanState *node);
结束扫描并释放资源。通常,释放palloc'd内存并不重要, 但是任何外部可见的资源都应该清除。在没有此类资源的常见情况下, 可以省略此函数(将指针设置为NULL)。