暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【手写数据库核心揭秘系列】第96讲 联接表达式的物理执行计划

开源无限 2025-06-05
84


💻 深耕数据库内核架构设计与开发十余年,曾主导多款高性能分布式数据库内核研发,攻克高并发、低延迟等核心技术难题。现倾力打造《从零手写数据库》系列教程,首次系统性公开数据库内核源码级实现细节!
🚀 从存储引擎、查询优化到分布式事务,手把手拆解核心模块;从语法解析树构建到执行计划生成,逐行代码还原设计精髓
🌟 无论你是数据库开发者、系统架构师,还是对底层技术充满好奇的极客,这里都有你想要的“硬核干货”!点击关注,与行业老兵共同探索数据库技术的星辰大海!


一、概述 


在物理执行计划生成阶段,首先处理联接数据源,在逻辑执行计划阶段已经将每个联接数据源都添加到了列表当中, 当然对于嵌套联接的情况,子联接数据源也会被添加到列表当中。

在物理计划中,对于联接子句的处理主要有以下内容:

  1. 将联接数据源转换为嵌套循环执行节点;因为当前联接只实现了一种执行算子,不同联接类型都使用这一种算法。
  2. 递归调用联接数据源处理函数,将嵌套联接数据源的子节点联接数据源也转换为嵌套循环执行节点;其实嵌套联接数据源会被转换为一棵二叉子树,它根节点和分支节点都会嵌套循环节点,叶子节点为目标列或者常量节点。
  3. 将上述转换后的联接执行子树添加到一个列表当中;
  4. 因为可能会存在多个子树的情况,当联接数据源子树多于一个时,将它们之间采用笛卡尔积的方式联接起来。

二、联接数据源处理 


联接执行节点处理和生成函数为:

    ounter(line
    Node *JoinPlanProcess(QueryStmt *queryStmt)

    将逻辑执行计划阶段生成的联接数据源,转换为联接执行节点,并将它们加到列表当中。

      ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
          for(listNode = ((List*)queryStmt->joinList)->head; listNode != NULL; listNode = listNode->next)
          {
              JoinTblInfo* joinTbl = (JoinTblInfo*)listNode->value;
              if(joinTbl->isPlan)
                  continue;


              node = TablePlanNode((Node*)joinTbl);


              if(node != NULL)
                  list = (List*)AppendList(list, node);
          }

      每遇到一个联接数据源,都会中序遍历递归处理它的左右子节点,

      在这个递归过程中,联接数据源列表中部分联接数据已经被处理,所以在遍历时,需要判断是否已经在执行计划当中,只有没在计划当中时再会被单独处理。

      三、生成联接执行节点  


      将联接数据源转换为联接执行节点,并将节点各成员初始化,然后递归处理它的左右子节点,直到叶子节点。

        ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
        Node* JoinPlanNode(JoinTblInfo *joinTbl)
        {
            NestLoopNode *nlNode = (NestLoopNode*)NewNode(NestLoopNode);


            nlNode->joinType = joinTbl->joinType;
            nlNode->parserNode = (Node*)joinTbl;
            nlNode->planInfo.execInfo = &nestloopStateInfo;
            nlNode->joinExpr = joinTbl->joinExpr;
            nlNode->lresult = NULL;
            nlNode->rresult = NULL;
            nlNode->needOuter = 1;


            joinTbl->isPlan = 1;


            if(joinTbl->leftTblInfo != NULL)
            {
                nlNode->leftplan = TablePlanNode(joinTbl->leftTblInfo);
            }


            if(joinTbl->rightTblInfo != NULL)
            {
                nlNode->rightplan = TablePlanNode(joinTbl->rightTblInfo);
            }


            return (Node*)nlNode;
        }

        成员赋值:

        • joinExpr,联接表达式;
        • execInfo,联接执行算子;目前用嵌套循环方式实现;
        • needOuter,联接执行参数,开始时先从外表开始扫描;
        • isPlan,添加到执行计划标志。

        四、生成联接执行计划树  


        最后将所有联接执行节点串联成树,独立的联接执行节点间通过无条件的内联接组织成一棵二叉树。

          ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
              if((list != NULL) && (list->length > 1))
              {
                  subplan = node;
                  for(listNode = list->head; listNode != NULL; listNode = listNode->next)
                  {
                      if(listNode->value == node)
                          continue;
                      subplan = CrossJoinPlan(subplan, listNode->value);
                  }
              }
              else 
              {
                  if(list != NULL)
                      subplan = list->head->value;
              }

          五、总结 


          本节内容主要实现联接表达式物理执行计划中的改变,实现位于exam_52目录下的plan.c文件中。

          🌟 点赞收藏,分享给身边的技术伙伴,关注我们,持续获取数据库内核开发的硬核干货!一起从源码级实现到分布式架构,解锁数据库技术的每一个核心细节!🚀


          【往期精彩推荐】

          【手写数据库核心揭秘系列】第95讲 联合查询,联接表达式的执行计划生成

          【手写数据库内核miniToadb】第36天 数据文件操作



          文章转载自开源无限,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论