前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Postgresql源码(64)查询执行——子模块Executor(2)执行前的数据结构和执行过程

Postgresql源码(64)查询执行——子模块Executor(2)执行前的数据结构和执行过程

作者头像
mingjie
发布2022-08-03 18:26:44
4670
发布2022-08-03 18:26:44
举报

上一篇说明了执行的框架,本篇深入分析执行细节。测试用例不变,还是分析之前的case。

0 总结

  • 下图中的planstate有四类:控制节点、扫描节点、连接节点、物化节点
    • 扫描节点公共父类:Scan
    • 连接节点公共父类:Join
  • Plan的子节点通过Plan的lefttree和righttree指针连接,构成计划树
  • 执行时,Planstate用于记录各节点的执行状态,estate中的es_tupleTable在节点间传递元组。
  • Excutor输入QueryDesc,包含plannedstmt树形结构;执行前用plannedstmt初始化节点状态树planstate,同时初始化全局状态信息estate。然后执行planstate根节点的函数指针,进入根节点业务处理函数(例如nestloop),pull模型向下层取数据拉动整个计划树的执行。
在这里插入图片描述
在这里插入图片描述

1 ExecutorRun执行前数据结构

执行计划:

  1. teach_course和teacher走hash连接,生成outer表(驱动表)
  2. course表做inner表
  3. 循环嵌套连接:course.no是连接键,位于course表的第一列。
代码语言:javascript
复制
explain select t.name, c.name, stu_num
from course as c, teach_course as tc, teacher as t
where c.no = tc.cno and tc.tno = t.no and c.name = 'Database System' and t.name = 'Jennifer';
                                    QUERY PLAN                                     
-----------------------------------------------------------------------------------
 Nested Loop  (cost=24.10..74.58 rows=1 width=68)
   ->  Hash Join  (cost=23.95..62.61 rows=61 width=40)
         Hash Cond: (tc.tno = t.no)
         ->  Seq Scan on teach_course tc  (cost=0.00..30.40 rows=2040 width=12)
         ->  Hash  (cost=23.88..23.88 rows=6 width=36)
               ->  Seq Scan on teacher t  (cost=0.00..23.88 rows=6 width=36)
                     Filter: ((name)::text = 'Jennifer'::text)
   ->  Index Scan using course_pkey on course c  (cost=0.15..0.20 rows=1 width=36)
         Index Cond: (no = tc.cno)
         Filter: ((name)::text = 'Database System'::text)

执行前的数据结构:

在这里插入图片描述
在这里插入图片描述

2 ExecutorRun执行过程

测试SQL

代码语言:javascript
复制
select t.name, c.name, stu_num
from course as c, teach_course as tc, teacher as t
where c.no = tc.cno and tc.tno = t.no and c.name = 'Database System' and t.name = 'Jennifer';

调试起点:b ExecutorRun

我们再看下这张图:

在这里插入图片描述
在这里插入图片描述

2.1 ExecNestLoop

nestloop需要从外表(outer表)中(驱动表)顺序扫描拿一条,在从内表(inner表)中找这条能连上的。具体在这个执行计划中:

  • 从hashjoin的结果中按顺序那一条(outer表)
  • 用这一条去indexscan找能连上的(去inner表上索引扫描)
  • 返回一条结果
在这里插入图片描述
在这里插入图片描述

执行过程

  1. 用Outerplan从驱动表里面拿一条
  2. 用这一条去innerplan里面找一条能连上的
  3. 返回
代码语言:javascript
复制
ExecNestLoop
  ...
  outerPlan = outerPlanState(node)    // left node
  innerPlan = innerPlanState(node)    // right node
  // loop until we return a qualifying join tuple
  for (;;)
    // 从outer表的计划上找到一条
    outerTupleSlot = ExecProcNode(outerPlan)
  // 完了去inner表里面拿一条(要能连得上的一条)
  innerTupleSlot = ExecProcNode(innerPlan)
    ExecIndexScan
      for (;;)
        // 【重要】注意这个函数,ExecScanFetch没有具体业务逻辑,这是个框架函数
        // ExecScanFetch用accessMtd拿到元组,在用recheckMtd检查元组是否符合要求
        // 这里用的是两个通用函数 IndexNext 和 IndexRecheck
        slot = ExecScanFetch(node, accessMtd, recheckMtd)
          // 进入bt堆栈
          IndexNext

2.2 ExecHashJoin

ExecHashJoin的逻辑是一个小型switch状态机,通过流转状态走完业务逻辑,读起来比较顺畅。

hashjoin会seqscan扫左表,同时把右表创建成一个哈希表(会带着过滤条件,并不是把所有元组都建到哈希表里面)

  • 从左表中拿一条
  • 用这一条去哈希表里面查询,如果能连上就返回一条
在这里插入图片描述
在这里插入图片描述

执行过程:

  1. 创建右节点的哈希表
  2. 从左节点拿一个元组
  3. 去哈希表中匹配
  4. 匹配上返回,匹配不上goto 2
代码语言:javascript
复制
ExecHashJoinImpl
  ExecHashTableCreate
  // 拿一条左表中的数据
  ExecHashJoinOuterGetTuple
    // T_SeqScanState
    slot = ExecProcNode(outerNode)
  // 找到能连上的tuple所在的bucket
  ExecHashGetBucketAndBatch
  ExecHashGetSkewBucket
  // 查找bucket
  ExecScanHashBucket
  // 找到连接元组

2.3 ExecSeqScan

seqscan为什么那么费CPU又效率低。 答:无等待无IO连续下面几件事情:

  1. 找buffer(没在需要IO上来)
  2. 在buffer找到合适的位置,用tuple->t_data指上去
  3. 拼tupleslot
  4. 返回
  5. 继续循环

上面5步不涉及IO、没有任何会sleep的逻辑,基本就是连续的函数调用、变量赋值,所以持续做会把单核打满。效率低是应为没条件一行一行全部都要扫一遍,慢是必然的。

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
SeqNext
  scandesc = table_beginscan
  table_scan_getnextslot
    slot->tts_tableOid = RelationGetRelid(sscan->rs_rd)
    heap_getnextslot
      heapgettup_pagemode
        heapgetpage
        BufferGetPage
        tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0 总结
  • 1 ExecutorRun执行前数据结构
  • 2 ExecutorRun执行过程
    • 2.1 ExecNestLoop
      • 2.2 ExecHashJoin
        • 2.3 ExecSeqScan
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档