一. 前言
本文将假设以一个以id为分区字段的表t1, 以SQL: select * from t1 where id > 2 and id < 5 为例讲述在OpenGuass中是如何进行分区裁剪的。如下图所示,本来t1有个6分区,但是OpenGuass会根据 id > 2 and id < 5的谓词条件进行无交集的分区裁剪,裁剪后实际扫描数据的时候,只会访问3个分区。
二. OpenGuass 分区裁剪过程
partitionPruningForRestrictInfo
partitionPruningForExpr
partitionPruningWalker
recordBoundaryFromOpExpr // 将根据谓词条件确认需要访问分区的上下界
// 下边的for循环将谓词条件逐个遍历,比如这里有id > 2 和id < 5
for(cell, expr->args) {
partitionPruningWalker(arg, context);
recordBoundaryFromOpExpr
// 根据谓词条件决定上下界,比如>2 的条件下界为2, <5的条件上界为5
if(strcmp(">", opName)) {
boundary->min[attrOffset] = PointerGetDatum(constArg);
}
if (strcmp("<", opName) {
boundary->max[attrOffset] = PointerGetDatum(constMax);
} ......
resultList = lappend(resultList, iterator) // 保存谓词条件与分区的交集
}
// 有了所有谓词条件的上下界后,将根据谓词连接是and 还是or 决定取交集还是并集
switch (expr->boolop) {
case AND_EXPR : intersectChildPruningResult // 将所有的谓词条件去交集保存为最后的谓词结果
case OR_EXPR : unionChildPruningResult // 取所有谓词条件的并集为最后的结果
}
// 如下的partitionPruningFromBoundary将根据上边获取的谓词条件与分区键的值比较,决定该分区的取舍
partitionPruningFromBoundary
bottomValue = pruningResult->boundary->min // 谓词条件的上下界
topValue = pruningResult->boundary->max
partitionRoutingForValueRange(u_sess->opt_cxt.bottom_seq) // 将谓词与分区键的较大值作为分区起始扫描值
getRangePartitionOid(keyValue) // 根据上下界的值找对应的分区oid
partitionRoutingForValueRange(u_sess->opt_cxt.top_seq) // 将谓词条件与分区键的较小值作为分区结束扫描值
getRangePartitionOid(keyValue) // 根据上下界的值找对应的分区oid
// 保存裁剪后需要扫描的分区
for (i = rangeStart; i <= rangeEnd; i++) {
rangeBms = bms_add_member(rangeBms, i)
}
pruningResult->bm_rangeSelectedPartitions = rangeBms // bm_rangeSelectedPartitions保存的是最后要扫描的分区的分区的列表。