openGauss之向量化执行引擎代码走读

一. 前言

        openGauss向量化执行引擎是指原来计算过程中一行元组一行元组的处理的方式改成一批元组一批地处理,从而减少调用栈和CPU切换开销,一般在大数据量聚合查询中会有较大的性能提升。本文主要以向量化做sum聚合为例走读代码了解openGauss中是怎么实现向量化计算能力的。

        向量化操作的执行计划如上所示,可以看到,向量化计算时,需要将tablescan的数据转成向量话数据计算,计算完成后再转成普通的行存数据输出。本文也按照这思路走读代码。

二. 生成向量化执行计划

     执行计划生成是指将普通的执行计划转成向量化执行计划,入口在try_vectorize_plan中:

try_vectorize_plan
    vectorize_plan
         // 对各种算子进行向量化转换,以SeqScan为例
         switch (nodeTag(result_plan)) {
             case T_SeqScan:
                 make_rowtove_plan
                     make_rowtovec
                         RowToVec* node = makeNode(RowToVec);   // 生成行转向量算子
                         plan->lefttree = lefttree;
         }
         
         if (IsVecOutput(top_plan))
             top_plan = (Plan*)make_vectorow(top_plan);   // 在最后的输出,还需要将向量转回行输出
三. 行转向量化

        因为openGauss的默认数据是行存的,为了能向量化执行,需要转成列存,列存后每行数据就可以保存很多行元组的数据,从而方便处理。openGauss中行转列的函数入口为ExecVecToRow,如下为代码走读过程:

ExecVecToRow
    if (BatchIsNull(current_batch)) {
        VectorEngine
           ExecRowToVec    // 现将所有行转成向量的batch
               ExecRowToVecBatchMode
                   ScanBatchResult *scanSlotBatch = ExecProcNode((PlanState*)seqScanState);  // 扫描一个页的元祖
                       ExecSeqScan
                          HeapamGetNextBatchMode
                              HeapGetTupPageBatchmode
                    VectorizeTupleBatchMode   // 一个页的元祖转换成向量
                        for (j = 0; j < rows; j++) {  // 一个页的每一行处理
                           tableam_tslot_formbatch(slots[j], pBatch, j, scanstate->maxcolId);
                               heap_slot_formbatch
                                   ScalarVector* pVector = &batch->m_arr[attno];  // 取出该列的列向量
                                   pVector->m_vals[cur_rows] = heapGetInitDefVal  // 在该列指定的行中保存元素,从而实现了行存到列存之间的转换
                               
                    }
                pOutBatch = ApplyProjectionAndFilterBatch  // 谓词初步裁量
    }
    
    for (int i = 0; i < state->nattrs; i++) {
       tuple->tts_values[i] = state->m_ttsvalues[tuple_subscript + i];  // 向量化中在转换成普通行元祖
    }
    

四. 向量化计算

如下以sum为例介绍怎么向量化进行批量计算的:

HashAggRunner::Run()
    Build();
       outer_batch = m_hashSource->getBatch();
       (this->*m_buildFun)(outer_batch);   // 构建Hash表
           HashAggRunner::buildAggTbl
               hashBatch  // 计算每行的hash值
               for (i = 0; i < rows; i++) {
                   AllocHashSlot<simple, true>(batch, i);   // 分区Hash存储空间并且将数据存放到对应的Hash位置上
                       HashAggRunner::AllocHashSlot
                           cell = (hashCell*)palloc(m_cellSize);   // 分配空间
                           initCellValue<simple, false>(batch, cell, i) // 往对应的Hash位置上存放数据    
               }
               BatchAggregation(batch);   // 批量做聚合
                   for (i = 0; i < m_aggNum; i++) {  // 所有的聚合算子
                       AggregationOnScalar
                           VecFunctionCallInvoke(fcinfo)  // 调用向量聚合的
                               vinterval_sum   // 以向量化做sum计算为例,会调用vinterval_sum
                                  for (i = 0; i < nrows; i++) {  // 批量聚合
                                     result = interval_pl
                                  }
                               
                   }
               
       
    p_res = Probe();   // 列存聚合的结果
    

五. 向量化转行

      向量化计算完成后,需要重新转成普通的行存数据进行输出,代码入口在ExecVecToRow中

ExecVecToRow
    DevectorizeOneBatch
       for (i = 0; i < cols; i++) {       // 列存又转回行存
           column = &current_batch->m_arr[i];
           for (j = 0; j < rows; j++)
               state->m_ttsisnull[j * cols + i] = IS_NULL(column->m_flag[j]);
           state->devectorizeFunRuntime[i](state, column, rows, cols, i);
               DevectorizeOneColumn
                   for (int j = 0; j < rows; j++) {
                       k = j * cols + i;     // 行存列存下标转换
                       switch (typid) {
                           state->m_ttsvalues[k] = xxx   // 根据类型填充行存的数据
                       }
                   }
              
       }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值