openGauss源码解析(49)
openGauss源码解析:存储引擎源码解析(17)
4. cstore访存接口和索引机制
cstore访存接口如表4-30所示,主要包括扫描、插入、删除和查询操作。
表4-30 cstore访存接口
接口名称 |
接口含义 |
---|---|
CStoreBeginScan |
开启cstore扫描 |
CStore::RunScan |
执行cstore扫描,根据执行计划,内层执行cstore顺序扫描或者cstore min-max过滤扫描 |
CStoreGetNextBatch |
继续扫描,返回下一批向量数组 |
CStoreEndScan |
结束cstore扫描 |
CStore::CStoreScan |
cstore顺序扫描 |
CStore::CStoreMinMaxScan |
cstore min-max过滤扫描 |
CStoreInsert::BatchInsert(VectorBatch) |
将输入的向量数组批量插入cstore表中 |
CStoreInsert::BatchInsert(bulkload_rows) |
将输入的多行数组插入cstore表中 |
CStoreInsert::BatchInsertCommon |
将一批多行数组(最多MAX_BATCH_ROWS行)插入cstore表各个列的CU文件中、插入对应CUDESC表记录、插入索引 |
CStoreInsert::InsertDeltaTable |
将一批多行数组插入cstore表对应的delta表中 |
InsertIdxTableIfNeed |
将一批多行数组插入cstore表的索引表中 |
CStoreDelete::PutDeleteBatch |
将一批待删除的向量数组暂存到局部数据结构中,如果达到局部内存上限,则触发一下删除操作 |
CStoreDelete::PutDeleteBatchForTable |
CStoreDelete::PutDeleteBatch对于普通cstore表的内层实现 |
CStoreDelete::PutDeleteBatchForPartition |
CStoreDelete::PutDeleteBatch对于分区cstore表的内层实现 |
CStoreDelete::PutDeleteBatchForUpdate |
CStoreDelete::PutDeleteBatch对于更新cstore表操作的内层实现(更新操作由删除操作和插入操作组合而成) |
CStoreDelete::ExecDelete |
执行cstore表删除,内层调用普通cstore表删除或分区cstore表删除 |
CStoreDelete::ExecDeleteForTable |
执行普通cstore表删除 |
CStoreDelete::ExecDeleteForPartition |
执行分区cstore表删除 |
CStoreDelete::ExecDelete(rowid) |
删除cstore表中特定一行的接口 |
CStoreUpdate::ExecUpdate |
执行cstore表更新 |
cstore表查询执行流程,可以参考图4-26中所示。其中,灰色部分实际上是在初始化cstore扫描阶段执行的,根据每个字段的具体类型,绑定不同的CU扫描和解析函数,主要有FillVector、FillVectorByTids、FillVectorLateRead3类CU扫描解析接口。
图4-26 cstore表查询流程示意图
cstore表插入执行流程,可以参考图4-27所示。其中灰色部分内的具体流程可以参考图4-24、图4-25中所示。当满足以下3个条件时,可以支持delta表插入:
(1) 打开enable_delta_store GUC参数。
(2) 该批向量数组为本次导入的最后一批向量数组。
(3) 该批向量数组的行数小于delta表插入的阈值。
图4-27 cstore表插入流程示意图
cstore表的删除流程主要分为两步。
(1) 如果存在delta表,那么先从delta表中删除满足谓词条件的记录。
(2) 在CUDESC表中更新待删除行所在CU的删除位图记录。
cstore表的更新操作由删除操作和插入操作组合而成,流程不再赘述。
openGauss的cstore表支持psort和cbtree两种索引。
psort索引是一种局部排序聚簇索引。psort索引表的组织形式也是cstore表,该cstore表的字段包括索引键中的各个字段,再加上对应的行号(TID)字段。如图4-28所示,将一定数量的记录按索引键经过排序聚簇之后,与TID字段共同拼装成向量数组之后,插入psort索引cstore表中,插入流程和上面cstore表插入流程相同。
图4-28 psort索引插入原理图
查询时如果使用psort索引扫描,会首先扫描psort索引cstore表(扫描方式和上面cstore表扫描流程相同)。在一个psort索引CU的内部,由于做了局部聚簇索引,因此可以使用基于索引键的二分查找方式,快速找到符合索引条件的记录在该psort索引中的行号,该行的TID字段值即为该条记录在cstore主表中的行号。上述流程如图4-29所示。值得一提的是由于做了局部聚簇索引,因此在索引cstore表扫描过程中,在真正加载索引表CU文件之前,可以通过CUDESC中的min max做到非常高效的初筛过滤。
图4-29 psort索引查询原理图
cstore表的cbtree索引和行存储表的B-Tree索引在结构和使用方式上几乎完全一致,相关原理可以参考行存储索引章节(“4.2.5 行存储索引机制”节),此处不再赘述。
openGauss cstore表索引对外提供的主要接口如表4-31所示。
表4-31 cstore表索引对外接口
接口名称 |
接口含义 |
psortgettuple |
通过psort索引,返回下一条满足索引条件的元组。伪接口,实际psort索引扫描通过CStore::RunScan实现 |
psortgetbitmap |
通过psort索引,返回满足索引条件的元组的tid bitmap。伪接口,实际psort索引扫描通过CStore::RunScan实现 |
psortbuild |
构建psort索引表数据。主要流程包括,从cstore主表中扫描数据、局部聚簇排序、插入到psort索引cstore表中 |
cbtreegettuple |
通过cbtree索引,返回下一条满足索引条件的元组。内部和btgettuple都是通过调用_bt_gettuple_internal函数实现的 |
cbtreegetbitmap |
通过cbtree索引,返回满足索引条件的元组的tid bitmap。内部和btgetbitmap都是通过调用_bt_next函数实现的 |
cbtreebuild |
构建cbtree索引表数据。内部实现与btbuild类似,先后调用_bt_spoolinit、CStoreGetNextBatch、_bt_spool、_bt_leafbuild和_bt_spooldestroy等几个主要函数实现。与btbuild区别在于,B-Tree的构建过程中,扫描堆表是通过heapam接口实现的,而cbtree扫描的是cstore表,因此使用的是CStoreGetNextBatch |