From 2f6eea23d6c5d75f983256f450b48d86e804b003 Mon Sep 17 00:00:00 2001 From: ChangerR Date: Mon, 15 May 2023 10:11:40 +0000 Subject: [PATCH] add a check rule when trigger groupby pullup --- .../rewrite/ob_transform_groupby_pullup.cpp | 343 +++++++++++++++--- src/sql/rewrite/ob_transform_groupby_pullup.h | 44 ++- .../rewrite/ob_transform_groupby_pushdown.cpp | 6 +- .../rewrite/ob_transform_groupby_pushdown.h | 2 +- src/sql/rewrite/ob_transform_or_expansion.cpp | 12 +- src/sql/rewrite/ob_transform_or_expansion.h | 2 +- src/sql/rewrite/ob_transform_rule.cpp | 16 +- src/sql/rewrite/ob_transform_rule.h | 2 + .../rewrite/ob_transform_semi_to_inner.cpp | 5 +- src/sql/rewrite/ob_transform_semi_to_inner.h | 2 +- .../ob_transform_subquery_coalesce.cpp | 2 +- src/sql/rewrite/ob_transform_win_magic.cpp | 1 + ...for_producer_consumer_schedule_mode.result | 2 + ...l_for_producer_consumer_schedule_mode.test | 3 +- 14 files changed, 369 insertions(+), 73 deletions(-) diff --git a/src/sql/rewrite/ob_transform_groupby_pullup.cpp b/src/sql/rewrite/ob_transform_groupby_pullup.cpp index b4e198fe7..ce3e0bbb6 100644 --- a/src/sql/rewrite/ob_transform_groupby_pullup.cpp +++ b/src/sql/rewrite/ob_transform_groupby_pullup.cpp @@ -15,6 +15,8 @@ #include "sql/rewrite/ob_transform_utils.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/optimizer/ob_optimizer_util.h" +#include "sql/optimizer/ob_log_subplan_scan.h" +#include "sql/optimizer/ob_log_table_scan.h" #include "common/ob_smart_call.h" using namespace oceanbase::sql; @@ -51,6 +53,7 @@ int ObTransformGroupByPullup::transform_one_stmt(common::ObIArray valid_views; + ObCostBasedPullupCtx pullup_ctx; ObTryTransHelper try_trans_helper; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; @@ -66,7 +69,6 @@ int ObTransformGroupByPullup::transform_one_stmt(common::ObIArraystmt_factory_, *ctx_->expr_factory_, stmt, @@ -75,13 +77,14 @@ int ObTransformGroupByPullup::transform_one_stmt(common::ObIArrayget_table_item_by_id(view_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("view is null", K(ret)); + } else if (OB_FALSE_IT(pullup_ctx.view_talbe_id_ = valid_views.at(i).table_id_)) { } else if (OB_FAIL(get_trans_view(trans_stmt, view_stmt))) { LOG_WARN("failed to get transform view", K(ret)); } else if (OB_FAIL(do_groupby_pull_up(view_stmt, valid_views.at(i)))) { LOG_WARN("failed to do pull up group by", K(ret)); } else if (OB_FAIL(accept_transform(parent_stmts, stmt, trans_stmt, - valid_views.at(i).need_merge_, - trans_happened))) { + valid_views.at(i).need_merge_, true, + trans_happened, &pullup_ctx))) { LOG_WARN("failed to accept transform", K(ret)); } else if (!trans_happened) { LOG_DEBUG("pull up not happen", K(trans_happened)); @@ -909,57 +912,24 @@ int ObTransformGroupByPullup::wrap_case_when(ObSelectStmt &child_stmt, } -int ObTransformGroupByPullup::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) +int ObTransformGroupByPullup::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) { int ret = OB_SUCCESS; - ObCostBasedPushDownCtx *push_down_ctx = static_cast(check_ctx); - if (OB_ISNULL(plan) || OB_ISNULL(push_down_ctx)) { + ObCostBasedPullupCtx *ctx = static_cast(check_ctx); + if (OB_ISNULL(ctx) || OB_ISNULL(plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); - } else if (OB_FAIL(check_nl_operator(plan->get_plan_root(), push_down_ctx, is_valid))) { - LOG_WARN("check nl operator failed", K(ret)); - } - return ret; -} - -int ObTransformGroupByPullup::check_nl_operator(ObLogicalOperator *op, ObCostBasedPushDownCtx *push_down_ctx, bool &is_valid) -{ - int ret = OB_SUCCESS; - const int64_t stmt_id = push_down_ctx->stmt_id_; - ObLogJoin *join = NULL; - if (OB_ISNULL(op) || OB_ISNULL(op->get_stmt())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("op is null", K(ret)); - } else if (stmt_id == op->get_stmt()->get_stmt_id()) { - if (log_op_def::LOG_JOIN == op->get_type()) { - if (OB_ISNULL(join = static_cast(op))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("static cast failed", K(ret)); - } else if (JoinAlgo::NESTED_LOOP_JOIN == join->get_join_algo() && join->get_nl_params().count() > 0) { - ObLogicalOperator *right_table = join->get_right_table(); - bool exist_group_by_op = false; - if (OB_ISNULL(right_table)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("right table is null", K(ret)); - } else if (push_down_ctx->new_table_relids_.overlap(right_table->get_table_set())) { - if (OB_FAIL(has_group_by_op(right_table, exist_group_by_op))) { - LOG_WARN("has group by op failed", K(ret)); - } else { - is_valid = !exist_group_by_op; - } - } - } else {} - } else {} - } else {} - - for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < op->get_num_of_child(); i++) { - if (OB_FAIL(SMART_CALL(check_nl_operator(op->get_child(i), push_down_ctx, is_valid)))) { - LOG_WARN("check nl operator failed", K(ret)); - } + } else if (is_trans_plan) { + //do nothing + } else if (OB_FAIL(check_original_plan_validity(plan->get_plan_root(), + ctx->view_talbe_id_, + is_valid))) { + LOG_WARN("failed to check plan validity", K(ret)); } return ret; } + int ObTransformGroupByPullup::has_group_by_op(ObLogicalOperator *op, bool &bret) { int ret = OB_SUCCESS; @@ -1099,3 +1069,284 @@ int ObTransformGroupByPullup::need_transform(const common::ObIArray parent_ops; + ObLogicalOperator *subplan = NULL; + ObSEArray column_exprs; + ObSEArray select_exprs; + ObSEArray group_exprs; + uint64_t groupby_nopushdown_cut_ratio = 1; + double group_ndv = 1.0; + double card = 1.0; + bool has_stats = true; + const ObSelectStmt *child_stmt = NULL; + if (OB_ISNULL(root) || + OB_ISNULL(ctx_) || + OB_ISNULL(ctx_->session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(root), K(ret)); + } else if (OB_FAIL(find_operator(root, parent_ops, view_table_id, subplan))) { + LOG_WARN("failed to find subplan scan operator", K(root), K(view_table_id), K(ret)); + } else if (OB_ISNULL(subplan) || parent_ops.empty()) { + //do nothing + } else if (OB_UNLIKELY(subplan->get_num_of_child() == 0) || + OB_ISNULL(subplan = subplan->get_child(ObLogicalOperator::first_child)) || + OB_ISNULL(subplan->get_stmt()) || + OB_UNLIKELY(!subplan->get_stmt()->is_select_stmt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FALSE_IT(child_stmt = static_cast(subplan->get_stmt()))) { + // do nothing + } else if (OB_FAIL(check_all_table_has_statistics(subplan, has_stats))) { + LOG_WARN("failed to check all table has statistics", K(ret)); + } else if (!has_stats) { + is_valid = false; + RESUME_OPT_TRACE + OPT_TRACE("check original plan has statistics:", has_stats); + STOP_OPT_TRACE + } else if (OB_FAIL(extract_columns_in_join_conditions(parent_ops, + view_table_id, + column_exprs))) { + LOG_WARN("failed to extract columns in join conditions", K(ret)); + } else if (OB_FAIL(ObTransformUtils::convert_column_expr_to_select_expr(column_exprs, + *child_stmt, + select_exprs))) { + LOG_WARN("failed to convert column exprs to select exprs", K(ret)); + } else if (OB_FAIL(get_group_by_subset(select_exprs, + child_stmt->get_group_exprs(), + group_exprs))) { + LOG_WARN("failed to get group by subset", K(ret)); + } else if (OB_FAIL(ctx_->session_info_->get_sys_variable(share::SYS_VAR__GROUPBY_NOPUSHDOWN_CUT_RATIO, + groupby_nopushdown_cut_ratio))) { + LOG_WARN("failed to get session variable", K(ret)); + } else if (OB_FAIL(calc_group_exprs_ndv(group_exprs, subplan, group_ndv, card))) { + LOG_WARN("failed to check group exprs", K(ret)); + } else { + double expansion_rate = card / group_ndv; + is_valid = expansion_rate < groupby_nopushdown_cut_ratio; + LOG_TRACE("check original plan", K(is_valid), K(group_exprs), K(group_ndv), K(expansion_rate)); + RESUME_OPT_TRACE + OPT_TRACE("check original plan group by exprs:", group_exprs); + OPT_TRACE("check original plan group by ndv:", group_ndv); + OPT_TRACE("check original plan expansion rate:", expansion_rate); + STOP_OPT_TRACE + } + return ret; +} + +int ObTransformGroupByPullup::find_operator(ObLogicalOperator* root, + ObIArray &parents, + uint64_t view_table_id, + ObLogicalOperator *&subplan_root) +{ + int ret = OB_SUCCESS; + subplan_root = NULL; + if (OB_ISNULL(root)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null logical operator", K(ret)); + } else if (log_op_def::LOG_SUBPLAN_SCAN == root->get_type() && + static_cast(root)->get_subquery_id() == view_table_id) { + subplan_root = root; + } else { + for (int64_t i = 0; OB_SUCC(ret) && NULL == subplan_root && i < root->get_num_of_child(); ++i) { + ObLogicalOperator *child = root->get_child(i); + if (OB_FAIL(SMART_CALL(find_operator(child, parents, view_table_id, subplan_root)))) { + LOG_WARN("failed to find operator", K(ret)); + } else if (NULL == subplan_root) { + //do nothing + } else if (parents.empty() || + parents.at(0)->get_stmt() == root->get_stmt()) { + if (OB_FAIL(parents.push_back(root))) { + LOG_WARN("failed to push back operator", K(ret)); + } + } + } + } + return ret; +} + +int ObTransformGroupByPullup::calc_group_exprs_ndv(const ObIArray &group_exprs, + ObLogicalOperator *subplan_root, + double &group_ndv, + double &card) +{ + int ret = OB_SUCCESS; + ObLogPlan *plan = NULL; + ObLogicalOperator *child_op = subplan_root; + group_ndv = 1.0; + if (OB_ISNULL(subplan_root) || + OB_ISNULL(plan = subplan_root->get_plan())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null logical operator", K(ret)); + } else if (OB_FAIL(find_base_operator(child_op))) { + LOG_WARN("failed to find base operator", K(ret)); + } else if (OB_ISNULL(child_op)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null logical operator", K(ret)); + } else { + card = child_op->get_card(); + plan->get_selectivity_ctx().init_op_ctx(&child_op->get_output_equal_sets(), card); + if (group_exprs.empty()) { + group_ndv = 1.0; + } else if (OB_FAIL(ObOptSelectivity::calculate_distinct(plan->get_update_table_metas(), + plan->get_selectivity_ctx(), + group_exprs, + card, + group_ndv))) { + LOG_WARN("failed to calculate distinct", K(ret)); + } else { /* do nothing */ } + } + return ret; +} + +int ObTransformGroupByPullup::find_base_operator(ObLogicalOperator *&root) +{ + int ret = OB_SUCCESS; + while (OB_SUCC(ret) && root != NULL && + (root->get_type() ==log_op_def::LOG_GROUP_BY || + root->get_type() == log_op_def::LOG_EXCHANGE)) { + if (OB_UNLIKELY(root->get_num_of_child() != 1) || + OB_ISNULL(root = root->get_child(ObLogicalOperator::first_child))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null logical operator", K(ret)); + } + } + return ret; +} + +int ObTransformGroupByPullup::extract_columns_in_join_conditions( + ObIArray &parent_ops, + uint64_t table_id, + ObIArray &column_exprs) +{ + int ret = OB_SUCCESS; + ObLogicalOperator *parent = NULL; + ObSEArray tmp_column_exprs; + for (int64_t i = 0; OB_SUCC(ret) && i < parent_ops.count(); ++i) { + if (OB_ISNULL(parent = parent_ops.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(parent), K(ret)); + } else if (log_op_def::LOG_JOIN == parent->get_type()) { + ObLogJoin *join_op = static_cast(parent); + + if (HASH_JOIN == join_op->get_join_algo() || + MERGE_JOIN == join_op->get_join_algo()) { + tmp_column_exprs.reuse(); + if (OB_FAIL(ObRawExprUtils::extract_column_exprs(join_op->get_equal_join_conditions(), + table_id, + tmp_column_exprs))) { + LOG_WARN("failed to extract column exprs", K(ret)); + } else if (OB_FAIL(append_array_no_dup(column_exprs, tmp_column_exprs))) { + LOG_WARN("failed to append array no dup", K(ret)); + } + } else if (NESTED_LOOP_JOIN == join_op->get_join_algo()) { + for (int64_t i = 0; OB_SUCC(ret) && i < join_op->get_other_join_conditions().count(); ++i) { + ObRawExpr *cond = NULL; + if (OB_ISNULL(cond = join_op->get_other_join_conditions().at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (!cond->has_flag(IS_JOIN_COND)) { + // do nothing + } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(cond, + table_id, + tmp_column_exprs))) { + LOG_WARN("failed to extract column exprs", K(ret)); + } else if (OB_FAIL(append_array_no_dup(column_exprs, tmp_column_exprs))) { + LOG_WARN("failed to append array no dup", K(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < join_op->get_nl_params().count(); ++i) { + tmp_column_exprs.reuse(); + if (OB_ISNULL(join_op->get_nl_params().at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("nl param is null", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(join_op->get_nl_params().at(i)->get_ref_expr(), + table_id, + tmp_column_exprs))) { + LOG_WARN("failed to extract column exprs", K(ret)); + } else if (OB_FAIL(append_array_no_dup(column_exprs, tmp_column_exprs))) { + LOG_WARN("failed to append array no dup", K(ret)); + } + } + } + } + } + return ret; +} + +int ObTransformGroupByPullup::get_group_by_subset(ObRawExpr *expr, + const ObIArray &group_exprs, + ObIArray &subset_group_exprs) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is null", K(ret)); + } else { + int64_t idx = -1; + if (expr->has_flag(IS_AGG) || expr->has_flag(IS_CONST)) { + //do nothing + } else if (OB_FAIL(ObTransformUtils::get_expr_idx(group_exprs, expr, idx))) { + LOG_WARN("get expr idx failed", K(ret)); + } else if (idx == -1) { //not found + for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { + if (OB_FAIL(SMART_CALL(get_group_by_subset(expr->get_param_expr(i), group_exprs, subset_group_exprs)))) { + LOG_WARN("check group by subset faield", K(ret)); + } + } + } else if (OB_FAIL(add_var_to_array_no_dup(subset_group_exprs, expr))) { + LOG_WARN("failed to add var to array no dump", K(ret)); + } + } + return ret; +} + +int ObTransformGroupByPullup::get_group_by_subset(ObIArray &exprs, + const ObIArray &group_exprs, + ObIArray &subset_group_exprs) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { + if (OB_FAIL(get_group_by_subset(exprs.at(i), group_exprs, + subset_group_exprs))) { + LOG_WARN("check group by exprs failed", K(ret)); + } + } + return ret; +} + +int ObTransformGroupByPullup::check_all_table_has_statistics(ObLogicalOperator *op, bool &has_stats) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(op)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (op->get_type() == log_op_def::LOG_TABLE_SCAN) { + ObLogTableScan *table_scan = static_cast(op); + ObLogPlan *plan = table_scan->get_plan(); + OptTableMeta* meta = NULL; + if (OB_ISNULL(plan)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_ISNULL(meta = plan->get_basic_table_metas() + .get_table_meta_by_table_id(table_scan->get_table_id()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else { + has_stats = meta->get_version() > 0; + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && has_stats && i < op->get_num_of_child(); ++i) { + if (OB_FAIL(SMART_CALL(check_all_table_has_statistics(op->get_child(i), has_stats)))) { + LOG_WARN("failed to check all table has statistics", K(ret)); + } + } + } + return ret; +} \ No newline at end of file diff --git a/src/sql/rewrite/ob_transform_groupby_pullup.h b/src/sql/rewrite/ob_transform_groupby_pullup.h index 3b11a4b49..309abbc8e 100644 --- a/src/sql/rewrite/ob_transform_groupby_pullup.h +++ b/src/sql/rewrite/ob_transform_groupby_pullup.h @@ -42,7 +42,7 @@ public: bool &trans_happened) override; protected: virtual int adjust_transform_types(uint64_t &transform_types) override; - virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) override; + virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) override; private: struct PullupHelper { PullupHelper(): @@ -77,10 +77,9 @@ private: K_(need_merge)); }; - struct ObCostBasedPushDownCtx { - ObCostBasedPushDownCtx() {}; - int64_t stmt_id_; - ObSqlBitSet<> new_table_relids_; + struct ObCostBasedPullupCtx { + ObCostBasedPullupCtx() {}; + uint64_t view_talbe_id_; }; int check_groupby_validity(const ObSelectStmt &stmt, bool &is_valid); @@ -147,10 +146,6 @@ private: ObRawExpr *not_null_column, ObRawExpr *&expr); - int check_nl_operator(ObLogicalOperator *op, - ObCostBasedPushDownCtx *push_down_ctx, - bool &is_valid); - int has_group_by_op(ObLogicalOperator *op, bool &bret); @@ -164,6 +159,37 @@ private: const int64_t current_level, const ObDMLStmt &stmt, bool &need_trans) override; + + int check_original_plan_validity(ObLogicalOperator* root, + uint64_t view_table_id, + bool &is_valid); + + int find_operator(ObLogicalOperator* root, + ObIArray &parents, + uint64_t view_table_id, + ObLogicalOperator *&subplan_op); + + int find_base_operator(ObLogicalOperator *&root); + + int extract_columns_in_join_conditions(ObIArray &parent_ops, + uint64_t table_id, + ObIArray &column_exprs); + + int get_group_by_subset(ObRawExpr *expr, + const ObIArray &group_exprs, + ObIArray &subset_group_exprs); + + int get_group_by_subset(ObIArray &exprs, + const ObIArray &group_exprs, + ObIArray &subset_group_exprs); + + int calc_group_exprs_ndv(const ObIArray &group_exprs, + ObLogicalOperator *subplan_root, + double &group_ndv, + double &card); + + int check_all_table_has_statistics(ObLogicalOperator *op, bool &has_stats); + private: // help functions int64_t get_count_sum_num(const ObIArray &exprs) diff --git a/src/sql/rewrite/ob_transform_groupby_pushdown.cpp b/src/sql/rewrite/ob_transform_groupby_pushdown.cpp index 858509677..38f4ee8e5 100644 --- a/src/sql/rewrite/ob_transform_groupby_pushdown.cpp +++ b/src/sql/rewrite/ob_transform_groupby_pushdown.cpp @@ -92,7 +92,7 @@ int ObTransformGroupByPushdown::transform_one_stmt(common::ObIArrayis_enable_hint(), + NULL != myhint && myhint->is_enable_hint(), false, trans_happened, &push_down_ctx))) { LOG_WARN("failed to accept transform", K(ret)); } else if (!trans_happened) { @@ -1578,13 +1578,15 @@ int ObTransformGroupByPushdown::construct_transform_hint(ObDMLStmt &stmt, void * return ret; } -int ObTransformGroupByPushdown::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) +int ObTransformGroupByPushdown::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) { int ret = OB_SUCCESS; ObCostBasedPushDownCtx *push_down_ctx = static_cast(check_ctx); if (OB_ISNULL(plan) || OB_ISNULL(push_down_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); + } else if (!is_trans_plan) { + // do nothing } else if (OB_FAIL(check_nl_operator(plan->get_plan_root(), push_down_ctx, is_valid))) { LOG_WARN("check nl operator failed", K(ret)); } diff --git a/src/sql/rewrite/ob_transform_groupby_pushdown.h b/src/sql/rewrite/ob_transform_groupby_pushdown.h index a85d63c08..235ced7c8 100644 --- a/src/sql/rewrite/ob_transform_groupby_pushdown.h +++ b/src/sql/rewrite/ob_transform_groupby_pushdown.h @@ -42,7 +42,7 @@ public: bool &trans_happened) override; protected: virtual int adjust_transform_types(uint64_t &transform_types) override; - virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) override; + virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) override; private: struct PushDownParam { ObSqlBitSet<> table_bit_index_; diff --git a/src/sql/rewrite/ob_transform_or_expansion.cpp b/src/sql/rewrite/ob_transform_or_expansion.cpp index 66626eb7d..3404367b2 100644 --- a/src/sql/rewrite/ob_transform_or_expansion.cpp +++ b/src/sql/rewrite/ob_transform_or_expansion.cpp @@ -169,7 +169,7 @@ int ObTransformOrExpansion::transform_in_where_conditon(ObIArray &pa } else if (OB_FAIL(merge_stmt(trans_stmt, spj_stmt, transformed_union_stmt))) { LOG_WARN("failed to merge stmt", K(ret)); } else if (OB_FAIL(accept_transform(parent_stmts, stmt, trans_stmt, - NULL != ctx.hint_, + NULL != ctx.hint_, false, trans_happened, &ctx))) { LOG_WARN("failed to accept transform", K(ret)); } else if (trans_happened && OB_FAIL(add_transform_hint(*trans_stmt, &ctx))) { @@ -431,7 +431,7 @@ int ObTransformOrExpansion::try_do_transform_inner_join(ObIArrayref_query_ = static_cast(trans_stmt))) { } else if (OB_FAIL(accept_transform(parent_stmts, stmt, origin_trans_stmt, - NULL != ctx.hint_, + NULL != ctx.hint_, false, trans_happened, &ctx))) { LOG_WARN("failed to accept transform", K(ret)); } else if (trans_happened && OB_FAIL(add_transform_hint(*trans_stmt, &ctx))) { @@ -548,7 +548,7 @@ int ObTransformOrExpansion::try_do_transform_left_join(ObIArray } else if (OB_FALSE_IT(NULL == view_table ? trans_stmt = trans_ref_query : view_table->ref_query_ = trans_ref_query)) { } else if (OB_FAIL(accept_transform(parent_stmts, stmt, trans_stmt, - NULL != ctx.hint_, + NULL != ctx.hint_, false, trans_happened, &ctx))) { LOG_WARN("failed to accept transform", K(ret)); } else if (trans_happened && OB_FAIL(add_transform_hint(*trans_stmt, &ctx))) { @@ -2584,7 +2584,7 @@ int ObTransformOrExpansion::preprocess_or_condition(ObSelectStmt &stmt, 5. outer/semi/anti join: use nlj with exec param push down or use merge/hash and origin plan is nlj */ -int ObTransformOrExpansion::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) +int ObTransformOrExpansion::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) { int ret = OB_SUCCESS; ObCostBasedRewriteCtx *ctx = static_cast(check_ctx); @@ -2593,6 +2593,8 @@ int ObTransformOrExpansion::is_expected_plan(ObLogPlan *plan, void *check_ctx, b if (OB_ISNULL(ctx) || OB_ISNULL(plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); + } else if (!is_trans_plan) { + // do nothing } else if (OB_FAIL(find_trans_log_set(plan->get_plan_root(), ctx->trans_id_, log_set))) { LOG_WARN("failed to get join operator", K(ret)); } else if (NULL == log_set) { diff --git a/src/sql/rewrite/ob_transform_or_expansion.h b/src/sql/rewrite/ob_transform_or_expansion.h index 1a0388eef..7c9cea1e3 100644 --- a/src/sql/rewrite/ob_transform_or_expansion.h +++ b/src/sql/rewrite/ob_transform_or_expansion.h @@ -111,7 +111,7 @@ public: bool &trans_happened) override; protected: virtual int adjust_transform_types(uint64_t &transform_types) override; - virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) override; + virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) override; virtual int transform_one_stmt_with_outline(common::ObIArray &parent_stmts, ObDMLStmt *&stmt, bool &trans_happened) override; diff --git a/src/sql/rewrite/ob_transform_rule.cpp b/src/sql/rewrite/ob_transform_rule.cpp index b3cd432ba..7f7d37649 100644 --- a/src/sql/rewrite/ob_transform_rule.cpp +++ b/src/sql/rewrite/ob_transform_rule.cpp @@ -285,6 +285,7 @@ int ObTransformRule::accept_transform(common::ObIArray &parent_ ObDMLStmt *&stmt, ObDMLStmt *trans_stmt, bool force_accept, + bool check_original_plan, bool &trans_happened, void *check_ctx /* = NULL*/) { @@ -293,7 +294,7 @@ int ObTransformRule::accept_transform(common::ObIArray &parent_ trans_happened = false; ObDMLStmt *top_stmt = parent_stmts.empty() ? stmt : parent_stmts.at(0).stmt_; bool is_expected = false; - bool dummy = false; + bool is_original_expected = false; ObDMLStmt *tmp1 = NULL; ObDMLStmt *tmp2 = NULL; cost_based_trans_tried_ = true; @@ -308,11 +309,14 @@ int ObTransformRule::accept_transform(common::ObIArray &parent_ } else if (OB_FAIL(evaluate_cost(parent_stmts, trans_stmt, true, trans_stmt_cost, is_expected, check_ctx))) { LOG_WARN("failed to evaluate cost for the transformed stmt", K(ret)); - } else if (stmt_cost_ >= 0 || !is_expected) { + } else if ((!check_original_plan && stmt_cost_ >= 0) || !is_expected) { trans_happened = is_expected && trans_stmt_cost < stmt_cost_; } else if (OB_FAIL(evaluate_cost(parent_stmts, stmt, false, - stmt_cost_, dummy, NULL))) { + stmt_cost_, is_original_expected, + check_original_plan ? check_ctx : NULL))) { LOG_WARN("failed to evaluate cost for the origin stmt", K(ret)); + } else if (!is_original_expected) { + trans_happened = is_original_expected; } else { trans_happened = trans_stmt_cost < stmt_cost_; } @@ -324,6 +328,7 @@ int ObTransformRule::accept_transform(common::ObIArray &parent_ OPT_TRACE("before transform cost:", stmt_cost_); OPT_TRACE("after transform cost:", trans_stmt_cost); OPT_TRACE("is expected plan:", is_expected); + OPT_TRACE("is expected original plan:", is_original_expected); LOG_TRACE("reject transform because the cost is increased or the query plan is unexpected", K_(ctx_->is_set_stmt_oversize), K_(stmt_cost), K(trans_stmt_cost), K(is_expected)); } else if (OB_FAIL(adjust_transformed_stmt(parent_stmts, trans_stmt, tmp1, tmp2))) { @@ -344,10 +349,11 @@ int ObTransformRule::accept_transform(common::ObIArray &parent_ return ret; } -int ObTransformRule::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) +int ObTransformRule::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) { UNUSED(plan); UNUSED(check_ctx); + UNUSED(is_trans_plan); is_valid = false; return OB_SUCCESS; } @@ -415,7 +421,7 @@ int ObTransformRule::evaluate_cost(common::ObIArray &parent_stm LOG_WARN("failed to get optimization cost", K(ret)); } else if (NULL == check_ctx) { // do nothing - } else if (OB_FAIL(is_expected_plan(plan, check_ctx, is_expected))) { + } else if (OB_FAIL(is_expected_plan(plan, check_ctx, is_trans_stmt, is_expected))) { LOG_WARN("failed to check transformed plan", K(ret)); } } diff --git a/src/sql/rewrite/ob_transform_rule.h b/src/sql/rewrite/ob_transform_rule.h index 3781ec50b..12c22e887 100644 --- a/src/sql/rewrite/ob_transform_rule.h +++ b/src/sql/rewrite/ob_transform_rule.h @@ -350,6 +350,7 @@ protected: ObDMLStmt *&stmt, ObDMLStmt *trans_stmt, bool force_accept, + bool check_original_plan, bool &trans_happened, void *check_ctx = NULL); @@ -423,6 +424,7 @@ private: virtual int is_expected_plan(ObLogPlan *plan, void *check_ctx, + bool is_trans_plan, bool& is_valid); bool skip_move_trans_loc() const diff --git a/src/sql/rewrite/ob_transform_semi_to_inner.cpp b/src/sql/rewrite/ob_transform_semi_to_inner.cpp index b34bc1a4d..502aec74c 100644 --- a/src/sql/rewrite/ob_transform_semi_to_inner.cpp +++ b/src/sql/rewrite/ob_transform_semi_to_inner.cpp @@ -94,6 +94,7 @@ int ObTransformSemiToInner::transform_one_stmt( LOG_TRACE("semi join can not transform to inner join", K(*semi_info)); } else if (OB_FAIL(accept_transform(parent_stmts, stmt, trans_stmt, !need_check_cost || ctx.hint_force_, + false, accepted, &ctx))) { LOG_WARN("failed to accept transform", K(ret)); } else if (!accepted) { @@ -1455,7 +1456,7 @@ int ObTransformSemiToInner::is_ignore_semi_info(const uint64_t semi_id, bool &ig return ret; } -int ObTransformSemiToInner::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) +int ObTransformSemiToInner::is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) { int ret = OB_SUCCESS; ObCostBasedRewriteCtx *ctx = static_cast(check_ctx); @@ -1465,6 +1466,8 @@ int ObTransformSemiToInner::is_expected_plan(ObLogPlan *plan, void *check_ctx, b if (OB_ISNULL(ctx) || OB_ISNULL(plan)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); + } else if (!is_trans_plan) { + //do nothing } else if (ctx->is_multi_join_cond_) { is_valid = true; } else if (OB_FAIL(find_operator(plan->get_plan_root(), diff --git a/src/sql/rewrite/ob_transform_semi_to_inner.h b/src/sql/rewrite/ob_transform_semi_to_inner.h index fe3efdc9f..eb6049f3e 100644 --- a/src/sql/rewrite/ob_transform_semi_to_inner.h +++ b/src/sql/rewrite/ob_transform_semi_to_inner.h @@ -45,7 +45,7 @@ public: bool &trans_happened) override; virtual int construct_transform_hint(ObDMLStmt &stmt, void *trans_params) override; protected: - int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool &is_valid) override; + int is_expected_plan(ObLogPlan *plan, void *check_ctx, bool is_trans_plan, bool &is_valid) override; private: enum TransformFlag {TO_INNER = 1, TO_AGGR_INNER = 2, TO_INNER_GBY = 4}; diff --git a/src/sql/rewrite/ob_transform_subquery_coalesce.cpp b/src/sql/rewrite/ob_transform_subquery_coalesce.cpp index e5b4c87fc..cf323eb2a 100644 --- a/src/sql/rewrite/ob_transform_subquery_coalesce.cpp +++ b/src/sql/rewrite/ob_transform_subquery_coalesce.cpp @@ -90,7 +90,7 @@ int ObTransformSubqueryCoalesce::transform_one_stmt(common::ObIArray &parent_ stmt, trans_stmt, NULL != myhint && myhint->is_enable_hint(), + false, accepted))) { LOG_WARN("accept transform failed", K(ret)); } else if (!accepted) { diff --git a/tools/deploy/mysql_test/test_suite/px/r/mysql/alloc_material_for_producer_consumer_schedule_mode.result b/tools/deploy/mysql_test/test_suite/px/r/mysql/alloc_material_for_producer_consumer_schedule_mode.result index 45b2ef8bb..c6265d29f 100644 --- a/tools/deploy/mysql_test/test_suite/px/r/mysql/alloc_material_for_producer_consumer_schedule_mode.result +++ b/tools/deploy/mysql_test/test_suite/px/r/mysql/alloc_material_for_producer_consumer_schedule_mode.result @@ -1,6 +1,8 @@ drop table if exists t1, t2; create table t1 (c1 int, c2 int, c3 int); create table t2 (c1 int, c2 int, c3 int); +call dbms_stats.gather_table_stats(NULL, 't1'); +call dbms_stats.gather_table_stats(NULL, 't2'); explain select /*+ use_px parallel(2) use_hash(c d) */ * from (select a.c2, b.c3 from (select /*+ use_hash(a, b) */ c1, c2, count(*) c3 from t1 group by 1, 2) a, (select c1, c2, count(*) c3 from t1 group by 1, 2) b where a.c1 = b.c1) c, (select c1, c2, count(*) c3 from t1 group by 1, 2) d where c.c2 = d.c2; Query Plan ==================================================================================== diff --git a/tools/deploy/mysql_test/test_suite/px/t/alloc_material_for_producer_consumer_schedule_mode.test b/tools/deploy/mysql_test/test_suite/px/t/alloc_material_for_producer_consumer_schedule_mode.test index 5738e9e29..b7c7c7a54 100644 --- a/tools/deploy/mysql_test/test_suite/px/t/alloc_material_for_producer_consumer_schedule_mode.test +++ b/tools/deploy/mysql_test/test_suite/px/t/alloc_material_for_producer_consumer_schedule_mode.test @@ -10,7 +10,8 @@ drop table if exists t1, t2; create table t1 (c1 int, c2 int, c3 int); create table t2 (c1 int, c2 int, c3 int); - +call dbms_stats.gather_table_stats(NULL, 't1'); +call dbms_stats.gather_table_stats(NULL, 't2'); # need material above hash join. (but root DFO not needed) explain select /*+ use_px parallel(2) use_hash(c d) */ * from (select a.c2, b.c3 from (select /*+ use_hash(a, b) */ c1, c2, count(*) c3 from t1 group by 1, 2) a, (select c1, c2, count(*) c3 from t1 group by 1, 2) b where a.c1 = b.c1) c, (select c1, c2, count(*) c3 from t1 group by 1, 2) d where c.c2 = d.c2;