©
本文档使用 PHP中文网手册 发布
索引访问方法必须提供的索引构造和维护函数有:
IndexBuildResult * ambuild (Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo);
创建一个新索引。索引关系已经物理上创建好了,但是是空的。必须用索引访问方
法要求的固定数据填充它,还有就是所有已经在表里的行。通常,ambuild
函数会调用 IndexBuildHeapScan()
扫描该表以获取现
有行并计算需要插入索引的键字。
bool aminsert (Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_tid, Relation heapRelation, IndexUniqueCheck checkUnique);
向现有索引插入一个新行。values和isnull数组给出需要制作索引的键字值, 而 heap_tid 是要被索引的TID。 如果该访问方法支持唯一索引(它的 pg_am. amcanunique 标志是真),那么checkUnique可以是真,在这种情况下, 该索引访问方法必须校验表中不存在冲突的行;参阅Section 51.5获取细节。 通常在执行唯一性检查时访问方法仅仅需要heapRelation参数(尽管那时它将通过查堆来 检查元组活性)。
这个函数的布尔结果值仅仅在checkUnique 是UNIQUE_CHECK_PARTIAL 时有意义。这种情况下一个“真”值意味着这个新条目是唯一可知的,反之,“假”意味着它可能不 是唯一的(而且一个延迟的唯一性校验必须是预定的)。对于其他情况的结果建议使用常量“假”。
有些索引可能不会为所有元组做索引。如果元组不被编入索引, aminsert
应该什么都不做而仅仅返回。
IndexBulkDeleteResult * ambulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state);
从索引中删除行。这是一个"大批删除"的操作,通常都是通过扫描整个索引,检查
每条记录,看看它是否需要被删除来实现的。可以调用传递进来的callback函数,调用风格是:callback(TID,
callback_state)returns bool,其作用是判断某个用其引用的 TID
标识的索引条目是否需要删除。必须返回 NULL 或者是一个 palloc 出来的,
包含删除操作之效果的统计的结构。如果不需要向amvacuumcleanup
传递信息,返回NULL也是OK的。
由于maintenance_work_mem 的限制,在删除多行的时候 ambulkdelete
可能需要被调用多次,stats参数是先前在这
个索引上的调用结果(在一个 VACUUM操作内部第一次调用的话则
是 NULL)。这将允许 AM 在整个操作过程中积累统计信息。典型的,如果传递
的 stats 不是 null 的话,ambulkdelete
将会
修改并返回相同的结构。
IndexBulkDeleteResult * amvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats);
在一个(置空)操作(一个或多个 ambulkdelete
调用)之后清理。虽然不必做任何返回索引状态之外的任何其他事情,但是它通常用于
批量清理,比如说回收空的索引页面。stats 是最后的 ambulkdelete
调用返回的东西或者NULL(如果因为没有行需要删除而未调用 ambulkdelete
的话)。如果结果不是NULL,那么它必须是一个 palloc 出来的结构。它包含的
统计信息将用于更新 pg_class并且由VACUUM报
告(如果给出了VERBOSE)。如果索引在VACUUM 操作
的过程中根本没有改变,那么返回NULL也是可以的,否则必须返回当前状态。
在PostgreSQL8.4时,amvacuumcleanup
将也会在一个ANALYZE完成时被调用。这时stats总是空
而且任何返回值都将会被忽略。这种情况可以通过检测info->
analyze_only来区分。我们建议,在这样的调用中访问方法除了做插入后
的清理外什么也不做,并且那是仅仅是在一个自动清理的工作流程中。
void amcostestimate (PlannerInfo *root, IndexOptInfo *index, List *indexQuals, RelOptInfo *outer_rel, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation);
估算一个索引扫描的开销。该函数在下面的Section 51.6中有详细的讨论。
bytea * amoptions (ArrayType *reloptions, bool validate);
为一个索引分析和验证 reloptions 数组,仅当一个索引存在非空reloptions数 组时才会被调用。reloptions是一个text数组,包含 name=value 格式的项。 该函数应当创建一个bytea值,该值将被拷贝进索引的relcache项的 rd_options 字段。bytea值的数据内容可以由访问方法定义, 不过目前所有的标准访问方法都使用StdRdOptions结构。当 validate为真时,如果任何一个选项不可识别或者含有非法值,该 函数都应当报告一个适当的错误信息;当validate为假时,非法 项应该被悄悄的忽略。当载入已经存储在pg_catalog中的选项时, validate为假,仅在访问方法已经改变了选项规则的时候才可能找 到非法项,在此情况下可以忽略废弃的项。如果默认行为正是想要的,那么返回 NULL也OK。
索引的目的当然是支持那些包含一个可以索引的WHERE条件 的行的扫描,这个条件通常叫修饰词或 扫描键字。索引扫描的语义在下面的Section 51.3里面有更完整的描述。 一个索引访问方法必须提供的与扫描有关的函数有:
IndexScanDesc ambeginscan (Relation indexRelation, int nkeys, ScanKey key);
开始一个新的扫描。key数组(长度是 nkeys)为该索引扫
描描述索引键字(可能是多个)。结果必须是一个palloc出来的结构。
由于实现的原因,索引访问方法必须通过调用RelationGetIndexScan()
来创建这个结构。在大多数情况下,amrescan
本身除了调用上面这个
函数之外几乎不干别的事情;索引扫描启动时的有趣部分在amrescan
里。
boolean amgettuple (IndexScanDesc scan, ScanDirection direction);
在给出的扫描里抓取下一个行,向给出的方向移动(在索引里向前或者向后)。如果抓取
到了行,则返回TRUE,如果没有抓到匹配的行,返回FALSE。
在为TRUE的时候,该行的TID存储在 scan 结构里。请注意"成功"只
是意味着索引包含一个匹配扫描键字的条目,并不是说该行仍然在堆中存在,
或者是能够通过调用着的快照检查(译注:MVCC 快照,用于判断事务边界内的行可视性)。
在成功时,amgettuple
必须把 scan->xs_recheck 也设
置成TRUE或者FALSE。FSLSA意味着索引条目确定匹配搜索关键值。
TRUE意味着这并不确定,而且用搜索关键值表示的条件在被读取之后必须再与堆元组核对。
这条规定支持"lossy"索引操作符。
注意复查仅仅对搜索条件扩大;一个部分索引谓语(if any)从不被amgettuple
调用程序复查。
amgetbitmap
函数仅仅在访问方法支持"bitmap"索引扫描
时需要被提供。如果不是的话,在pg_am行的amgetbitmap
区域必须被设为零。
int64 amgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
在给出的扫描抓取多个行并且把它们添加到提供的调用TIDBitmap
中去,返回获取的元组的数量(这可能仅仅是一个粗略计数,事实上一些AMs不会
检测副本)。当把元组地址插入到点阵时,amgetbitmap
可以指明复校
扫描条件对特定的元组地址是必需的。 这个与amgettuple
的 xs_recheck输出函数是相似的。注意:照当前情况,维持这个特性是与维持维持位
图本身的损坏存储相关联的,因而调用方会为可复核的元重新检查扫描情况和部分索
引谓词(若有的话)。无论如何,那不会总是为真。 amgetbitmap
和
amgettuple
不能被用于相同的索引扫描;正如在Section 51.3,当使用amgetbitmap
的时候也有其他的限制条件。
amgetbitmap
函数仅仅在访问方法支持"bitmap"索引扫描时
需要被提供。如果不是的话,在pg_am行的 amgetbitmap区域必须被设为零。
void amrescan (IndexScanDesc scan, ScanKey key);
重启开始给出的扫描,可能使用的是一个新的扫描键字(要想继续使用原来的键字,
给 key)传递一个 NULL)。请注意,不可能改变键字的个数。实际上
这个重新开始的特性是在一个嵌套循环连接选取了一个新的外层行,因此需要一个
新的键字比较值,但扫描键字的结构仍然相同的时候使用的。这个函数也被
RelationGetIndexScan()
调用,因此这个函数既用于索引扫描的初
始化设置,也用于重复扫描。
void amendscan (IndexScanDesc scan);
结束扫描并释放资源。不应该释放scan本身,但访问方法内部使用的任 何锁或者销都应该释放。
void ammarkpos (IndexScanDesc scan);
标记当前扫描位置。访问方法只需要支持每次扫描里面有一个被记住的扫描位置。
void amrestrpos (IndexScanDesc scan);
把扫描恢复到最近标记的位置。
通常,任何索引访问方法函数的pg_proc记录都应该显示正确
数目的参数,只是把类型都声明为类型internal(因为大多数参数的类型
都是 SQL 不识别的类型,并且不希望用户直接调用该函数)。返回类型根据具体情况
声明为 void, internal, 或boolean。唯一的例外
是 amoptions
,它应当被声明为接受 text[]和bool
并返回 bytea。这样就允许客户端代码执行 amoptions
以选项设置的有效性。