其执行状态节点BitmapIndexScanState与IndexScanState也很相似,但多出了表示索引关键字属性数组及其长度的字段。BitmapIndexScan和IndexScan的执行过程也类似,只是在BitmapIndexScan处理过程中,初始化函数ExecInitBitmapIndexScan使用index_beginscan_bitmap函数初始化扫描状态,MultiExecBitmapIndexScan函数将调用index_getbitmap生成位图,并将其存放在执行状态记录节点的biss_result字段中。
typedef struct BitmapIndexScanState { ScanState ss; /* its first field is NodeTag */ TIDBitmap *biss_result; bitmap to return output into, or NULL ScanKey biss_ScanKeys; Skey structures for index quals int biss_NumScanKeys; number of ScanKeys IndexRuntimeKeyInfo *biss_RuntimeKeys; info about Skeys that must be evaluated at runtime int biss_NumRuntimeKeys; number of RuntimeKeys IndexArrayKeyInfo *biss_ArrayKeys; info about Skeys that come from ScalarArrayOpExprs int biss_NumArrayKeys; number of ArrayKeys bool biss_RuntimeKeysReady; true if runtime Skeys have been computed ExprContext *biss_RuntimeContext; expr context for evaling runtime Skeys Relation biss_RelationDesc; index relation descriptor IndexScanDesc biss_ScanDesc; index scan descriptor } BitmapIndexScanState; 6.BitmapHeapScan上面介绍的BitmapIndexScan节点将输出位图而不是元组,为了根据位图获取实际的元组,PostgreSQL提供了BitmapHeapScan节点从BitmapIndexScan输出的位图中获取元组。
BitmapHeapScan节点定义如下所示,该节点在Scan的基础上仅扩展了约束条件检査字段(bitmapqualorig),该字段与IndexScan节点的indexqualorig功能相同。当并发事务修改并提交了当前处理的元组时,需要重新扫描更新后的元组是否满足约束条件,而不是重新获取位图,因此将直接使用该表达式进行条件计算。BitmapHeapScan有且仅有一个子节点(左子节点),显然这个左子节点必须是提供位图输出的计划节点。
typedef struct BitmapHeapScan { Scan scan; List *bitmapqualorig; /* index quals, in standard expr form */ } BitmapHeapScan;初始化函数ExecInitBitmapHeapScan会根据节点中的scanrelid初始化扫描描述符ss_currentScanDesc。其他的初始化设置在执行过程中进行。
执行函数 ExecBitmapHeapScan 会将 BitmapHeapNext 函数指针传递给 ExecScan, ExecScan 使用BitmapHeapNext 获取元组。BitmapHeapNext 首先判断 BitmapHeapScanState 的 tbm (位图)是否为空,如果为空则调用MultiExecProcNode从左子节点获取位图,并调用tbm_begin_iterate初始化tbmiterator。如果需要预取还要调用 tbm_begin_iterate 初始化 prefetch_iterator,并将 prefetch_pages 置 0, prefetch_target设置为-1。然后执行过程会利用tbmiterator遍历位图获取物理元组的偏移量,然后从对应的缓冲区中按照偏移量取出元组并返回。
typedef struct BitmapHeapScanState { ScanState ss; /* its first field is NodeTag */ List *bitmapqualorig; execution state for bitmapqualorig expressions TIDBitmap *tbm; bitmap obtained from child index scan(s) TBMIterator *tbmiterator; iterator for scanning current pages TBMIterateResult *tbmres; current-page data long exact_pages; total number of exact pages retrieved long lossy_pages; total number of lossy pages retrieved TBMIterator *prefetch_iterator; iterator for prefetching ahead of current page int prefetch_pages; # pages prefetch iterator is ahead of current int prefetch_target; target prefetch distance } BitmapHeapScanState;清理过程ExecEndBitmapHeapScan需要调用左子节点的清理函数,然后清理tbmiterator、prefetch_iterator以及tbm位图,最后清理扫描描述符并关闭打开的表。
7.TidScan 节点PostgreSQL系统专用于标识元组物理位置的数据类型被称作TID (Tuple Identifier),一个TID由块号和块内偏移量组成,系统属性ctid被定义为此种类型。
PostgreSQL 自带的表是堆表,数据按行存储在HEAP PAGE中,在btree索引中,除了存储字段的value,还会存储对应的ctid(即行号),检索记录也是通过行号进行检索。 因此通过行号是可以快速检索到记录的。
行号的写法是(page_number, item_number),数据块从0开始编号,行号从1开始编号。
举例:
postgres=# select ctid ,* from zxc; ctid | id | name -------+----+---------- (0,4) | 1 | asdftest (0,5) | 3 | asdftest (0,6) | 9 | asdftest (3 行)那么我们可以用ctid来访问数据:
postgres=# select * from zxc where ctid = '(0,5)'::tid; id | name ----+---------- 3 | asdftest (1 行)同时,在定义游标后,可以使用“UPDATE/DELETE…WHERE CURRENT OF…”语句对当前游标位置的元组进行修改/删除。可以参考这里:[](http://www.postgres.cn/docs/9.5/sql-update.html)