diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index edc4298c773ceac2f010b53c060549ff305f659f..e04ebcf9120f84e0268d0f1550b84cddb1528cd4 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -245,6 +245,7 @@ static const struct config_enum_entry rewrite_options[] = { {"predpushforce", PRED_PUSH_FORCE, false}, {"disable_pullup_expr_sublink", SUBLINK_PULLUP_DISABLE_EXPR, false}, {"enable_sublink_pullup_enhanced", SUBLINK_PULLUP_ENHANCED, false}, + {"rownum_to_limit_enhanced", ROWNUM_TO_LIMIT_ENHANCED, false}, {NULL, 0, false} }; diff --git a/src/gausskernel/optimizer/plan/planner.cpp b/src/gausskernel/optimizer/plan/planner.cpp index ad34b3abc295283e774dfddd0c8214f53f989f27..acb13bde676d9ef50f7ecadc15f718ffe32adf60 100755 --- a/src/gausskernel/optimizer/plan/planner.cpp +++ b/src/gausskernel/optimizer/plan/planner.cpp @@ -3290,6 +3290,8 @@ static Plan* grouping_planner(PlannerInfo* root, double tuple_fraction) rel_info = best_path->parent; + result_plan = replacRownumLsToLimit(root, result_plan); + /* if it is an foreign rel, try to create foreign plan continue */ if (rel_info != NULL && rel_info->fdwroutine != NULL) { need_try_fdw_plan = true; diff --git a/src/gausskernel/optimizer/prep/preprownum.cpp b/src/gausskernel/optimizer/prep/preprownum.cpp index bcb28bc01ce0cc72a6fa2bc421d8bd40f7225620..0b257de25094dc3ffee3855ddf10e87677146247 100755 --- a/src/gausskernel/optimizer/prep/preprownum.cpp +++ b/src/gausskernel/optimizer/prep/preprownum.cpp @@ -28,6 +28,7 @@ */ #include "optimizer/prep.h" +#include "optimizer/planmain.h" #include "nodes/makefuncs.h" #include "utils/int8.h" @@ -439,4 +440,119 @@ static Node* process_rownum_ne(Query* parse, OpExpr* qual, bool isOrExpr) return makeBoolConst(true, false); } } + +/* rownum optimize remove rownum <\<= const filter adn return a limit value */ +int64 removeRownumFilter(List** quals, PlannerInfo* root) +{ + ListCell* lc = NULL; + ListCell* lcPrev = NULL; + ListCell* lcNext = NULL; + Node* exprNode = NULL; + bool matched = false; + int64 limitVal = -1; + /* avoid exception */ + if (quals == NULL || *quals == NULL) + return -1; + /* deal expr and expr */ + for (lc = list_head(*quals); lc; lc = lcNext) { + /* do not use foreach cause we delete list */ + lcNext = lnext(lc); + exprNode = (Node*)lfirst(lc); + /* we only handle op expr . do not conctern 'or expr' OR other expr has rownum */ + if (IsA(exprNode, OpExpr)) { + /* first, check plan->qual is a rownum < const */ + if (is_optimizable_rownum_opexpr(root, (OpExpr*)exprNode)) { + switch (((OpExpr*)exprNode)->opno) { + case INT8LTOID: + case INT84LTOID: + case INT82LTOID: + case NUMERICLTOID: { + /* operator < */ + if (try_extract_rownum_limit((OpExpr*)exprNode, &limitVal)) { + *quals = list_delete_cell(*quals, lc, lcPrev); + limitVal--; + matched = true; + } + break; + } + case INT8LEOID: + case INT84LEOID: + case INT82LEOID: + case NUMERICLEOID: { + /* operator <= */ + if (try_extract_rownum_limit((OpExpr*)exprNode, &limitVal)) { + *quals = list_delete_cell(*quals, lc, lcPrev); + matched = true; + } + break; + } + default: + break; + } + } + } + if (!matched) { + lcPrev = lc; + } else { + /* we only deal one rownum < xx when many rownum < xx existed */ + break; + } + + } + return limitVal; +} + +Plan* replacRownumLsToLimit(PlannerInfo* root, Plan* lefttree) +{ + if (!lefttree) + return NULL; + + /* open Guc */ + if (!ENABLE_ROWNUM_TO_LIMIT_ENHANCED()) + return lefttree; + + /* sonme plans that we don't use this rule */ + if (IsA(lefttree, BaseResult) || + IsA(lefttree, ModifyTable) || + IsA(lefttree, Append) || + IsA(lefttree, MergeAppend) || + IsA(lefttree, RecursiveUnion) || + IsA(lefttree, StartWithOp) || + IsA(lefttree, BitmapAnd) || + IsA(lefttree, BitmapOr) || + IsA(lefttree, CteScan) || + IsA(lefttree, ExtensiblePlan)) { + /* just return origin plan */ + return lefttree; + } + + List** quals = &lefttree->qual; + int64 limitVal = -1; + Node* limitNode = NULL; + limitVal = removeRownumFilter(quals, root); + /* means nothing in quals now ,check join filter */ + if (limitVal < 0 && *quals == NIL) { + switch (nodeTag(lefttree)) { + case T_VecNestLoop: + case T_NestLoop: + case T_VecMergeJoin: + case T_MergeJoin: + case T_HashJoin: + case T_VecHashJoin: + quals = &((HashJoin*)lefttree)->join.joinqual; + break; + default: + break; + } + limitVal = removeRownumFilter(quals, root); + } + + /* means we do not have any trensform here */ + if (limitVal < 0) + return lefttree; + limitNode = (Node*)makeConst(INT8OID, -1, InvalidOid, sizeof(int64), Int64GetDatum(limitVal), + false, true); + /* return a plan with new limit node */ + return (Plan*)make_limit(root, lefttree, NULL, limitNode, 0, 0); +} #endif diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index 5ae677c24fbaf98748abf88589ca26a90ca05bba..cea21e900caee84c694649934276c509c28517cb 100755 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -111,6 +111,6 @@ extern UNIONALL_SHIPPING_TYPE precheck_shipping_union_all(Query *subquery, Node /* judge if it is possible to optimize ROWNUM */ extern bool ContainRownumQual(const Query *parse); - +extern Plan* replacRownumLsToLimit(PlannerInfo* root, Plan* lefttree); #endif /* PREP_H */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index ff38a9ca2c9f9069ca883731861d7a2deebb787a..b129a1d912567eafed0ca8d45427ce3640d5e7b2 100755 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -400,7 +400,8 @@ typedef enum { PRED_PUSH_NORMAL = (1 << 7), PRED_PUSH_FORCE = (1 << 8), SUBLINK_PULLUP_DISABLE_EXPR = (1 << 9), /* disable pull sublink in expr clause */ - SUBLINK_PULLUP_ENHANCED = (1 << 10) + SUBLINK_PULLUP_ENHANCED = (1 << 10), + ROWNUM_TO_LIMIT_ENHANCED = (1 << 11) /* enhance rownum < or <= const treate as limit const */ } rewrite_param; typedef enum { @@ -456,6 +457,9 @@ typedef enum { #define ENABLE_SUBLINK_PULLUP_ENHANCED() \ ((SUBLINK_PULLUP_ENHANCED) & (uint)u_sess->attr.attr_sql.rewrite_rule) +#define ENABLE_ROWNUM_TO_LIMIT_ENHANCED() \ + ((ROWNUM_TO_LIMIT_ENHANCED) & (uint)u_sess->attr.attr_sql.rewrite_rule) + #define ENABLE_PRED_PUSH_ALL(root) \ ((ENABLE_PRED_PUSH(root) || ENABLE_PRED_PUSH_NORMAL(root) || ENABLE_PRED_PUSH_FORCE(root)) && permit_predpush(root))