opeGauss 之BitmapOr算子代码走读

一. 前言

        在openGauss中,BitmapOr算子扫描是指谓词条件是索引列的or条件时,将多个or条件的索引谓词先组成一个需要扫描元组的BitmapOr扫描算子,然后再通过BitmapOr算子的tid信息去扫描元组,从而减少or条件带来的随机扫描过多的问题,如下所示:

      本文主要通过走读代码了解openGauss是怎么实现BitmapOr算子的功能的。

二. 执行计划生成

       执行计划生成主要是如何在堆扫描下生成一个BitmapOr算子,BitmapOr算子包含所要扫描的元组信息。执行计划生成的入口在create_index_paths函数中,主要的代码流程如下所示:

create_index_paths
    indexpaths = generate_bitmap_or_paths(root, rel, rel->baserestrictinfo, NIL, false);
        foreach (lc, clauses) {
            if (!restriction_is_or_clause(rinfo))     // 只支持or语句
                continue;
                
            foreach (j, ((BoolExpr*)rinfo->orclause)->args) {  // 遍历各个or条件
                build_paths_for_OR
                    match_clauses_to_index(index, clauses, &clauseset);   // 检查索引和谓词的匹配情况
                    indexpaths = build_index_paths   // 每个or条件只是建立一个普通索引
                    result = list_concat(result, indexpaths);  // 把当前的索引建出来的路径保存到结果中
                bitmapqual = choose_bitmap_and(root, rel, indlist, globalIndexList); // 合并多索引情况下的bitmap和挑选代价最小的索引
                    for (i = 0; i < npaths; i++) {
                            if (i == 0 || chooseInfo.costsofar < bestcost) {
                                bestpaths = chooseInfo.paths;
                                bestcost = chooseInfo.costsofar;
                             }
                    }
                pathlist = lappend(pathlist, bitmapqual);
            }
            
            bitmapqual = (Path*)create_bitmap_or_path(root, rel, pathlist);  // 所有约束参数的索引连起来形成bitmap索引
                cost_bitmap_or_node(pathnode, root);
                    foreach (l, path->bitmapquals) {
                        cost_bitmap_tree_node(subpath, &subCost, &subselec);
                        selec += subselec;   // bitmap or的代价为各个or索引的代价之和
                    }   
        }
    indexpaths = generate_bitmap_or_paths(root, rel, joinorclauses, rel->baserestrictinfo, false); // 如果有or条件的话,也利用or条件作为约束生成一个新的bitmap path
    
    bitmapqual = choose_bitmap_and(root, rel, bitindexpaths); // 如果有多个bitmap索引路径生成,挑选出代价最小的
    bpath = create_bitmap_heap_path(bitmapqual);  //生成最后的堆扫描路径,bitmapqual条件为上述生成的bitmapor路径
    add_path(root, rel, (Path*)bpath);   // 保存路径

三. 算子层的实现

     算子层的实现入口在BitmapHeapTblNext函数中,代码流程如下所示:

BitmapHeapTblNext
    if (tbm == NULL) {    初始化需要扫描元组tid的bitmap
        MultiExecProcNode(outerPlanState(node));  // 获取需要访问的元组的tid,并且生成bitmap
            MultiExecBitmapIndexScan  
                scan_handler_idx_getbitmap(scandesc, tbm)
                    index_getbitmap(scan, bitmap)
                        btgetbitmap_internal(IndexScanDesc scan, TIDBitmap *tbm)
                            for (;;) {    // 根据谓词条件确认访问元组的上下界,并且将对应的位置加入到bitmap中
                                tbm_handler._add_tuples(tbm, heapTid, 1, false, currPartOid, bucketid); // 把索引的元组位置转成bitmap
                            }
        TableScanBitmapNextBlock(scan, tbmres, &node->ss.ps.state->have_current_xact_date)
            heapam_scan_bitmap_next_block
                hscan->rs_base.rs_cbuf = ReleaseAndReadBuffer();   // 拿到buff
                for (curslot = 0; curslot < tbmres->ntuples; curslot++) {
                    OffsetNumber offnum = tbmres->offsets[curslot];
                    hscan->rs_base.rs_vistuples[ntup++] = ItemPointerGetOffsetNumber  // 获取位置信息
                }
    }
    TableScanBitmapNextTuple
        HeapamScanBitmapNextTuple
            targoffset = hscan->rs_base.rs_vistuples[hscan->rs_base.rs_cindex];
            lp = PageGetItemId(dp, targoffset);   // 获取到元组所在的位置
            hscan->rs_ctup.t_data = (HeapTupleHeader)PageGetItem((Page)dp, lp);  // 拿到数据
            hscan->rs_base.rs_cindex++;   // ++ 指向下一次读取的位置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值