扫描算子----NodeIndexscan.cpp解析

引言

上一篇文章我学习了基本的扫描算子SeqScan,跟踪学习了主要的执行流程。这篇文章我将学习索引扫描算子IndexScan。

代码位置

src\gausskernel\runtime\executor\nodeIndexscan.cpp

名词解释

索引

1.什么是索引

数据库索引是为了提高查询速度而设立了一种数据结构。例如,日常生活中查字典时,可以通过拼音或者部首+笔画数快速地查找汉字,这里的拼音、部首、笔顺等都可以算作索引,如果没有了索引,就只能阅读整本字典,一一查找所需的汉字,这与建立索引相比,无疑是效率很低的做法。因此,建立索引能显著提高查询的速度和效率。

同样,数据库中,默认扫描方式是全表扫描,而建立了索引之后,扫描时会直接定位到索引值对应的行数,大大减少遍历的次数。

2.索引适用的条件

索引是一种数据结构,会占用一定的存储空间,并且需要额外维护,不是所有情况下都适合建立索引。例如:

  1. 经常INSERT、DELETE、UPDATE 的字段不适合建立索引,因为,每此执行这些语句后都要更新索引。
  2. 数据过滤性差的字段不适合建立索引,例如性别。对过滤性差的字段建立索引提高的效率并不高,甚至会负提升。
  3. 当表较小时不适合建立索引,此时建立索引提高的效率不足以补偿建立索引带来的维护以及存储成本。
3.索引的数据结构

索引采用B+ Tree作为其数据结构。

一个B+ Tree有如下特征:

  1. 非叶子节点最多有m(m>=2)个孩子结点,最少有[m/2]+1个孩子结点([]是取整函数)。
  2. 只有叶子结点存储表中字段的实际行号。
  3. 每个结点都存储索引key。
  4. 叶子结点间通过链表连接起来。

结构示意如图(图中是一颗三叉B+ Tree):

B+树

图中数字代表key。例如根节点5 28 65代表p1子树里所有节点的key必须在[5,28)内,p2子树里所有节点的key必须在[28,65)内,p3子树结点的key>=65。

Data即为通过索引key值定位到的数据。

关于B+ Tree的插入和删除等操作,这里就不再讲解,有兴趣的读者可以在网上搜索相关内容。

4.索引采用B+ Tree的好处
  1. 索引效率高,占用内存少的情况下能存入大量的索引。
  2. 适用性广泛,能较好地支持单点查询,范围查询等。

代码解读

ExecIndexScan

IndexSCan算子的关键代码是ExecIndexScan函数,其代码如下。

 
  1. //代码清单1
  2. TupleTableSlot* ExecIndexScan(IndexScanState* node)
  3. {
  4. /*
  5. * If we have runtime keys and they've not already been set up, do it now.
  6. */
  7. if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady) {
  8. /*
  9. * set a flag for partitioned table, so we can deal with it specially
  10. * when we rescan the partitioned table
  11. */
  12. if (node->ss.isPartTbl) {
  13. if (PointerIsValid(node->ss.partitions)) {
  14. node->ss.ss_ReScan = true;
  15. ExecReScan((PlanState*)node);
  16. }
  17. } else {
  18. ExecReScan((PlanState*)node);
  19. }
  20. }
  21. return ExecScan(&node->ss, (ExecScanAccessMtd)IndexNext, (ExecScanRecheckMtd)IndexRecheck);
  22. }

传入参数

ExecIndexScan函数的传入参数是一个IndexScanState*类型的指针。

IndexScanState结构体定义如下:

 
  1. typedef struct IndexScanState {
  2. ScanState ss; /* its first field is NodeTag */
  3. List* indexqualorig;
  4. ScanKey iss_ScanKeys;
  5. int iss_NumScanKeys;
  6. ScanKey iss_OrderByKeys;
  7. int iss_NumOrderByKeys;
  8. IndexRuntimeKeyInfo* iss_RuntimeKeys;
  9. int iss_NumRuntimeKeys;
  10. bool iss_RuntimeKeysReady;
  11. ExprContext* iss_RuntimeContext;
  12. Relation iss_RelationDesc;
  13. IndexScanDesc iss_ScanDesc;
  14. List* iss_IndexPartitionList;
  15. LOCKMODE lockMode;
  16. Relation iss_CurrentIndexPartition;
  17. } IndexScanState;

主要字段解释如下:

类型命名含义
ScanStatess扫描状态基类
List*indexqualorig索引限定表达式的执行状态
ScanKeyiss_ScanKeys索引里key值
intiss_NumScanKeys扫描时的key值数量
IndexRuntimeKeyInfo*iss_RuntimeKeys当前key
intiss_NumRuntimeKeys当前key数量
ScanKeyiss_OrderByKeys排序key
intiss_NumOrderByKeys排序key数量

执行过程

如果结点正在被运行,则调用ExecReScan重置扫描,更新新的参数信息。

然后调用ExecScan函数并返回一个元组。

小结

本篇文章中我学习了IndexScan算子的关键函数,并且介绍了opengauss中索引及其采用的数据结构。下一篇文章:TidScan算子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值