[FEAT MERGE] 4.3 optimizer enhancement
Co-authored-by: 2149 <260391947@qq.com> Co-authored-by: akaError <lzg020616@163.com> Co-authored-by: jinmaoli <lijinmao.csmaster@gmail.com>
This commit is contained in:
		| @ -1287,15 +1287,18 @@ int ObSelectLogPlan::allocate_window_function_as_top(const WinDistAlgo dist_algo | ||||
|                                                      const bool match_parallel, | ||||
|                                                      const bool is_partition_wise, | ||||
|                                                      const bool use_hash_sort, | ||||
|                                                      const bool use_topn_sort, | ||||
|                                                      const ObIArray<OrderItem> &sort_keys, | ||||
|                                                      ObLogicalOperator *&top) | ||||
|                                                      ObLogicalOperator *&top, | ||||
|                                                      const ObIArray<ObRawExpr *> *qualify_filters, | ||||
|                                                      double origin_sort_card) | ||||
| { | ||||
|   const int32_t role_type = ObLogWindowFunction::WindowFunctionRoleType::NORMAL; | ||||
|   const int64_t range_dist_keys_cnt = 0; | ||||
|   const int64_t range_dist_pby_prefix = 0; | ||||
|   return allocate_window_function_as_top(dist_algo, win_exprs, match_parallel, is_partition_wise, | ||||
|                                          use_hash_sort, role_type, sort_keys, range_dist_keys_cnt, | ||||
|                                          range_dist_pby_prefix, top, NULL, NULL); | ||||
|                                          use_hash_sort, use_topn_sort, role_type, sort_keys, range_dist_keys_cnt, | ||||
|                                          range_dist_pby_prefix, top, qualify_filters, origin_sort_card, NULL, NULL); | ||||
| } | ||||
|  | ||||
| int ObSelectLogPlan::allocate_window_function_as_top(const WinDistAlgo dist_algo, | ||||
| @ -1303,11 +1306,14 @@ int ObSelectLogPlan::allocate_window_function_as_top(const WinDistAlgo dist_algo | ||||
|                                                      const bool match_parallel, | ||||
|                                                      const bool is_partition_wise, | ||||
|                                                      const bool use_hash_sort, | ||||
|                                                      const bool use_topn_sort, | ||||
|                                                      const int32_t role_type, | ||||
|                                                      const ObIArray<OrderItem> &sort_keys, | ||||
|                                                      const int64_t range_dist_keys_cnt, | ||||
|                                                      const int64_t range_dist_pby_prefix, | ||||
|                                                      ObLogicalOperator *&top, | ||||
|                                                      const ObIArray<ObRawExpr *> *qualify_filters, | ||||
|                                                      double origin_sort_card, | ||||
|                                                      ObOpPseudoColumnRawExpr *wf_aggr_status_expr,  /* default null */ | ||||
|                                                      const ObIArray<bool> *pushdown_info /* default null */) | ||||
| { | ||||
| @ -1332,6 +1338,7 @@ int ObSelectLogPlan::allocate_window_function_as_top(const WinDistAlgo dist_algo | ||||
|     window_function->set_child(ObLogicalOperator::first_child, top); | ||||
|     window_function->set_role_type(ObLogWindowFunction::WindowFunctionRoleType(role_type)); | ||||
|     window_function->set_use_hash_sort(use_hash_sort); | ||||
|     window_function->set_use_topn_sort(use_topn_sort); | ||||
|     if (range_dist_keys_cnt > 0) { | ||||
|       window_function->set_ragne_dist_parallel(true); | ||||
|       window_function->set_rd_pby_sort_cnt(range_dist_pby_prefix); | ||||
| @ -1347,6 +1354,13 @@ int ObSelectLogPlan::allocate_window_function_as_top(const WinDistAlgo dist_algo | ||||
|         window_function->set_aggr_status_expr(wf_aggr_status_expr); | ||||
|       } | ||||
|     } | ||||
|     if (OB_SUCC(ret)) { | ||||
|       if (NULL != qualify_filters && OB_FAIL(window_function->get_filter_exprs().assign(*qualify_filters))) { | ||||
|         LOG_WARN("assign win filters failed", K(ret)); | ||||
|       } else if (use_topn_sort) { | ||||
|         window_function->set_origin_sort_card(origin_sort_card); | ||||
|       } | ||||
|     } | ||||
|     if (OB_FAIL(ret)) { | ||||
|     } else if (OB_FAIL(window_function->compute_property())) { | ||||
|       LOG_WARN("failed to compute property", K(ret)); | ||||
| @ -4737,6 +4751,7 @@ int ObSelectLogPlan::candi_allocate_window_function() | ||||
|   } else if (OB_FAIL(candi_allocate_subplan_filter_for_exprs(candi_subquery_exprs))) { | ||||
|     LOG_WARN("failed to do allocate subplan filter", K(ret)); | ||||
|   } else if (OB_FAIL(candi_allocate_window_function_with_hint(stmt->get_window_func_exprs(), | ||||
|                                                               stmt->get_qualify_filters(), | ||||
|                                                               win_func_plans))) { | ||||
|     LOG_WARN("failed to allocate window function with hint", K(ret)); | ||||
|   } else if (!win_func_plans.empty()) { | ||||
| @ -4744,6 +4759,7 @@ int ObSelectLogPlan::candi_allocate_window_function() | ||||
|   } else if (OB_FAIL(get_log_plan_hint().check_status())) { | ||||
|     LOG_WARN("failed to generate plans with hint", K(ret)); | ||||
|   } else if (OB_FAIL(candi_allocate_window_function(stmt->get_window_func_exprs(), | ||||
|                                                     stmt->get_qualify_filters(), | ||||
|                                                     win_func_plans))) { | ||||
|     LOG_WARN("failed to allocate window function", K(ret)); | ||||
|   } else { | ||||
| @ -4773,6 +4789,7 @@ int ObSelectLogPlan::candi_allocate_window_function() | ||||
| // 4. method matched | ||||
| // window functions in win_func_exprs must keep the same ordering with win_func_exprs_ in stmt | ||||
| int ObSelectLogPlan::candi_allocate_window_function_with_hint(const ObIArray<ObWinFunRawExpr*> &win_func_exprs, | ||||
|                                                               const ObIArray<ObRawExpr*> &qualify_filters, | ||||
|                                                               common::ObIArray<CandidatePlan> &total_plans) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
| @ -4802,7 +4819,8 @@ int ObSelectLogPlan::candi_allocate_window_function_with_hint(const ObIArray<ObW | ||||
|                                     orig_top->get_output_equal_sets(), | ||||
|                                     orig_top->get_output_const_exprs(), | ||||
|                                     orig_top->get_card(), | ||||
|                                     orig_top->get_is_at_most_one_row()); | ||||
|                                     orig_top->get_is_at_most_one_row(), | ||||
|                                     qualify_filters); | ||||
|     while (OB_SUCC(ret) && !candi_plans.empty() && !remaining_exprs.empty()) { | ||||
|       tmp_plans.reuse(); | ||||
|       if (OB_FAIL(init_win_func_helper_with_hint(candi_plans, | ||||
| @ -4834,8 +4852,10 @@ int ObSelectLogPlan::candi_allocate_window_function_with_hint(const ObIArray<ObW | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (OB_SUCC(ret) && OB_FAIL(total_plans.assign(candi_plans))) { | ||||
|       LOG_WARN("failed to assign candidate plans", K(ret)); | ||||
|     if (OB_SUCC(ret)) { | ||||
|       if (OB_FAIL(total_plans.assign(candi_plans))) { | ||||
|         LOG_WARN("failed to assign candidate plans", K(ret)); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return ret; | ||||
| @ -4944,6 +4964,9 @@ int ObSelectLogPlan::init_win_func_helper_with_hint(const ObIArray<CandidatePlan | ||||
|                                             win_func_helper.wf_aggr_status_expr_))) { | ||||
|       LOG_WARN("failed to build inner wf aggr status expr", K(ret)); | ||||
|     } | ||||
|     if (OB_SUCC(ret) && is_valid) { | ||||
|       win_func_helper.need_qualify_filter_ = remaining_exprs.empty(); | ||||
|     } | ||||
|     LOG_TRACE("finish init win_func_helper with hint. ", K(is_valid), K(win_func_helper)); | ||||
|   } | ||||
|   return ret; | ||||
| @ -4968,6 +4991,20 @@ int ObSelectLogPlan::calc_win_func_helper_with_hint(const ObLogicalOperator *op, | ||||
|     LOG_WARN("failed to calc ndvs and pby oby prefix", K(ret)); | ||||
|   } else if (OB_FAIL(calc_partition_count(win_func_helper))) { | ||||
|     LOG_WARN("failed to get partition count", K(ret)); | ||||
|   } else if (OB_ISNULL(win_func_helper.win_dist_hint_)) { | ||||
|     ret = OB_ERR_UNEXPECTED; | ||||
|     LOG_WARN("unexpected null", K(ret)); | ||||
|   } else { | ||||
|     const ObWindowDistHint *hint = win_func_helper.win_dist_hint_; | ||||
|     const ObWindowDistHint::WinDistOption &option = hint->get_win_dist_options().at(win_func_helper.win_op_idx_); | ||||
|     if (!option.use_topn_sort_) { | ||||
|       win_func_helper.enable_topn_ = false; | ||||
|       win_func_helper.topn_const_ = NULL; | ||||
|     } else if (OB_FAIL(init_wf_topn_option(win_func_helper, true))) { | ||||
|       LOG_WARN("choose topn filter failed", K(ret)); | ||||
|     } else if (!win_func_helper.enable_topn_) { | ||||
|       is_valid = false; | ||||
|     } | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
| @ -5017,6 +5054,7 @@ int ObSelectLogPlan::check_win_dist_method_valid(const WinFuncOpHelper &win_func | ||||
| } | ||||
|  | ||||
| int ObSelectLogPlan::candi_allocate_window_function(const ObIArray<ObWinFunRawExpr*> &win_func_exprs, | ||||
|                                                     const ObIArray<ObRawExpr*> &qualify_filters, | ||||
|                                                     ObIArray<CandidatePlan> &total_plans) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
| @ -5036,13 +5074,15 @@ int ObSelectLogPlan::candi_allocate_window_function(const ObIArray<ObWinFunRawEx | ||||
|                                     orig_top->get_output_equal_sets(), | ||||
|                                     orig_top->get_output_const_exprs(), | ||||
|                                     orig_top->get_card(), | ||||
|                                     orig_top->get_is_at_most_one_row()); | ||||
|                                     orig_top->get_is_at_most_one_row(), | ||||
|                                     qualify_filters); | ||||
|     for (int64_t i = 0; OB_SUCC(ret) && i < candi_plans.count(); ++i) { | ||||
|       OPT_TRACE("generate window function for plan:", candi_plans.at(i)); | ||||
|       if (OB_FAIL(generate_window_functions_plan(win_func_helper, | ||||
|                                                  status_exprs, | ||||
|                                                  total_plans, | ||||
|                                                  candi_plans.at(i)))) { | ||||
|                                                  candi_plans.at(i) | ||||
|                                                  ))) { | ||||
|         LOG_WARN("failed to allocate window functions", K(ret)); | ||||
|       } else { /*do nothing*/ } | ||||
|     } | ||||
| @ -5095,6 +5135,7 @@ int ObSelectLogPlan::generate_window_functions_plan(WinFuncOpHelper &win_func_he | ||||
|                                          methods, | ||||
|                                          si, | ||||
|                                          status_exprs, | ||||
|                                          remaining_exprs.empty(), | ||||
|                                          win_func_helper))) { | ||||
|           LOG_WARN("failed to init win func helper", K(ret)); | ||||
|         } else { | ||||
| @ -5151,9 +5192,9 @@ int ObSelectLogPlan::create_one_window_function(CandidatePlan &candidate_plan, | ||||
|                                               part_cnt))) { | ||||
|     LOG_WARN("failed to check win func need sort", K(ret)); | ||||
|   } else if (OB_FAIL(create_range_list_dist_win_func(top, | ||||
|                                                      win_func_helper, | ||||
|                                                      part_cnt, | ||||
|                                                      all_plans))) { | ||||
|                                                       win_func_helper, | ||||
|                                                       part_cnt, | ||||
|                                                       all_plans))) { | ||||
|     LOG_WARN("failed to create range list dist window functions", K(ret)); | ||||
|   } else if (OB_FAIL(create_none_dist_win_func(top, | ||||
|                                                win_func_helper, | ||||
| @ -5275,6 +5316,7 @@ int ObSelectLogPlan::init_win_func_helper(const ObIArray<ObWinFunRawExpr*> &orde | ||||
|                                           const ObIArray<WinDistAlgo> &methods, | ||||
|                                           const int64_t splict_idx, | ||||
|                                           ObIArray<ObOpPseudoColumnRawExpr*> &status_exprs, | ||||
|                                           bool is_last_group, | ||||
|                                           WinFuncOpHelper &win_func_helper) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
| @ -5294,6 +5336,12 @@ int ObSelectLogPlan::init_win_func_helper(const ObIArray<ObWinFunRawExpr*> &orde | ||||
|     ObOpPseudoColumnRawExpr *status_expr = NULL; | ||||
|     const int64_t start = 0 == splict_idx ? 0 : split.at(splict_idx - 1); | ||||
|     const int64_t end = split.at(splict_idx); | ||||
|     if (!is_last_group || splict_idx != split.count() - 1) { | ||||
|       //only alloc qualify filter on the top win func op | ||||
|       win_func_helper.need_qualify_filter_ = false; | ||||
|     } else { | ||||
|       win_func_helper.need_qualify_filter_ = true; | ||||
|     } | ||||
|     for (int64_t i = start; OB_SUCC(ret) && i < end; ++i) { | ||||
|       if (OB_FAIL(win_func_helper.ordered_win_func_exprs_.push_back(ordered_win_func_exprs.at(i))) | ||||
|           || OB_FAIL(win_func_helper.pby_oby_prefixes_.push_back(pby_oby_prefixes.at(i)))) { | ||||
| @ -5325,6 +5373,11 @@ int ObSelectLogPlan::init_win_func_helper(const ObIArray<ObWinFunRawExpr*> &orde | ||||
|     } else { | ||||
|       status_exprs.at(win_func_helper.win_op_idx_) = win_func_helper.wf_aggr_status_expr_; | ||||
|     } | ||||
|     if (OB_SUCC(ret)) { | ||||
|       if (OB_FAIL(init_wf_topn_option(win_func_helper, false))) { | ||||
|         LOG_WARN("choose topn filter failed", K(ret)); | ||||
|       } | ||||
|     } | ||||
|     LOG_TRACE("finish init win_func_helper. ", K(win_func_helper)); | ||||
|   } | ||||
|   return ret; | ||||
| @ -5936,6 +5989,8 @@ int ObSelectLogPlan::create_none_dist_win_func(ObLogicalOperator *top, | ||||
|   const ObIArray<ObWinFunRawExpr*> &win_func_exprs = win_func_helper.ordered_win_func_exprs_; | ||||
|   const ObIArray<OrderItem> &sort_keys = win_func_helper.sort_keys_; | ||||
|   bool is_local_order = false; | ||||
|   ObRawExpr *topn_const = NULL; | ||||
|   bool is_with_ties = false; | ||||
|   if (OB_ISNULL(top)) { | ||||
|     ret = OB_ERR_UNEXPECTED; | ||||
|     LOG_WARN("get unexpected null", K(ret)); | ||||
| @ -5965,17 +6020,25 @@ int ObSelectLogPlan::create_none_dist_win_func(ObLogicalOperator *top, | ||||
|   } | ||||
|  | ||||
|   if (OB_SUCC(ret) && need_normal_sort) { | ||||
|     ObLogicalOperator *normal_sort_top= top; | ||||
|     ObLogicalOperator *normal_sort_top = top; | ||||
|     bool use_topn = win_func_helper.enable_topn_ | ||||
|                     && win_func_helper.partition_exprs_.empty() | ||||
|                     && NULL != win_func_helper.topn_const_; | ||||
|     if (OB_FAIL(allocate_sort_and_exchange_as_top(normal_sort_top, exch_info, sort_keys, need_sort, | ||||
|                                                   prefix_pos, is_local_order))) { | ||||
|                                                   prefix_pos, is_local_order, | ||||
|                                                   use_topn ? win_func_helper.topn_const_ : NULL, /* topn_expr */ | ||||
|                                                   use_topn ?  win_func_helper.is_fetch_with_ties_ : false /* is_fetch_with_ties */))) { | ||||
|       LOG_WARN("failed to allocate sort and exchange as top", K(ret)); | ||||
|     } else if (OB_FAIL(allocate_window_function_as_top(WinDistAlgo::WIN_DIST_NONE, | ||||
|                                                        win_func_exprs, | ||||
|                                                        single_part_parallel, | ||||
|                                                        is_partition_wise, | ||||
|                                                        false, /* use hash sort */ | ||||
|                                                        use_topn, /* use topn sort */ | ||||
|                                                        sort_keys, | ||||
|                                                        normal_sort_top))) { | ||||
|                                                        normal_sort_top, | ||||
|                                                        win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL, | ||||
|                                                        use_topn ? win_func_helper.origin_sort_card_ : 0))) { | ||||
|       LOG_WARN("failed to allocate window function as top", K(ret)); | ||||
|     } else if (OB_FAIL(all_plans.push_back(CandidatePlan(normal_sort_top)))) { | ||||
|       LOG_WARN("failed to push back", K(ret)); | ||||
| @ -5985,12 +6048,15 @@ int ObSelectLogPlan::create_none_dist_win_func(ObLogicalOperator *top, | ||||
|   if (OB_SUCC(ret) && need_hash_sort) { | ||||
|     ObLogicalOperator *hash_sort_top= top; | ||||
|     OrderItem hash_sortkey; | ||||
|      bool use_part_topn = win_func_helper.enable_topn_ | ||||
|                           && prefix_pos == 0 | ||||
|                           && NULL != win_func_helper.topn_const_; | ||||
|     if (OB_FAIL(create_hash_sortkey(part_cnt, sort_keys, hash_sortkey))) { | ||||
|       LOG_WARN("failed to create hash sort key", K(ret), K(part_cnt), K(sort_keys)); | ||||
|     } else if (OB_FAIL(allocate_sort_and_exchange_as_top(hash_sort_top, exch_info, sort_keys, need_sort, | ||||
|                                                          prefix_pos, is_local_order, | ||||
|                                                          NULL, /* topn_expr */ | ||||
|                                                          false, /* is_fetch_with_ties */ | ||||
|                                                          use_part_topn ? win_func_helper.topn_const_ : NULL, /* topn_expr */ | ||||
|                                                          use_part_topn ? win_func_helper.is_fetch_with_ties_ : false, /* is_fetch_with_ties */ | ||||
|                                                          &hash_sortkey))) { | ||||
|       LOG_WARN("failed to allocate sort and exchange as top", K(ret)); | ||||
|     } else if (OB_FAIL(allocate_window_function_as_top(WinDistAlgo::WIN_DIST_NONE, | ||||
| @ -5998,8 +6064,11 @@ int ObSelectLogPlan::create_none_dist_win_func(ObLogicalOperator *top, | ||||
|                                                        single_part_parallel, | ||||
|                                                        is_partition_wise, | ||||
|                                                        true, /* use hash sort */ | ||||
|                                                        use_part_topn, /* use partition topn sort */ | ||||
|                                                        sort_keys, | ||||
|                                                        hash_sort_top))) { | ||||
|                                                        hash_sort_top, | ||||
|                                                        win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL, | ||||
|                                                        use_part_topn ? win_func_helper.origin_sort_card_ : 0))) { | ||||
|       LOG_WARN("failed to allocate window function as top", K(ret)); | ||||
|     } else if (OB_FAIL(all_plans.push_back(CandidatePlan(hash_sort_top)))) { | ||||
|       LOG_WARN("failed to push back", K(ret)); | ||||
| @ -6064,11 +6133,14 @@ int ObSelectLogPlan::create_range_list_dist_win_func(ObLogicalOperator *top, | ||||
|                                                     single_part_parallel, | ||||
|                                                     is_partition_wise, | ||||
|                                                     false, /* use hash sort */ | ||||
|                                                     false, /* use hash topn sort */ | ||||
|                                                     ObLogWindowFunction::WindowFunctionRoleType::NORMAL, | ||||
|                                                     sort_keys, | ||||
|                                                     range_dist_keys.count(), | ||||
|                                                     pby_prefix, | ||||
|                                                     top))) { | ||||
|                                                     top, | ||||
|                                                     win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL, | ||||
|                                                     0))) { | ||||
|     LOG_WARN("failed to allocate window function as top", K(ret)); | ||||
|   } else if (OB_FAIL(all_plans.push_back(CandidatePlan(top)))) { | ||||
|     LOG_WARN("failed to push back", K(ret)); | ||||
| @ -6169,6 +6241,8 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|   bool is_partition_wise = false; | ||||
|   const ObIArray<ObWinFunRawExpr*> &win_func_exprs = win_func_helper.ordered_win_func_exprs_; | ||||
|   const ObIArray<OrderItem> &sort_keys = win_func_helper.sort_keys_; | ||||
|   ObRawExpr *topn_const = NULL; | ||||
|   bool is_with_ties = false; | ||||
|   if (OB_ISNULL(top)) { | ||||
|     ret = OB_ERR_UNEXPECTED; | ||||
|     LOG_WARN("get unexpected null", K(ret)); | ||||
| @ -6195,6 +6269,9 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|   } | ||||
|   if (OB_SUCC(ret) && need_normal_sort) { | ||||
|     ObLogicalOperator *normal_sort_top= top; | ||||
|     bool use_topn = win_func_helper.enable_topn_ | ||||
|                     && win_func_helper.partition_exprs_.empty() | ||||
|                     && NULL != win_func_helper.topn_const_; | ||||
|     if (!need_pushdown && | ||||
|         OB_FAIL(create_normal_hash_dist_win_func(normal_sort_top, | ||||
|                                                 win_func_exprs, | ||||
| @ -6202,7 +6279,11 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|                                                 sort_keys, | ||||
|                                                 need_sort, | ||||
|                                                 prefix_pos, | ||||
|                                                 NULL))) { | ||||
|                                                 NULL, | ||||
|                                                 use_topn ?  win_func_helper.topn_const_ : NULL, | ||||
|                                                 use_topn ?  win_func_helper.is_fetch_with_ties_ : false, | ||||
|                                                 win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL, | ||||
|                                                 use_topn ? win_func_helper.origin_sort_card_ : 0))) { | ||||
|       LOG_WARN("failed to create normal hash dist window function", K(ret)); | ||||
|     } else if (need_pushdown && | ||||
|                OB_FAIL(create_pushdown_hash_dist_win_func(normal_sort_top, | ||||
| @ -6212,7 +6293,8 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|                                                           win_func_helper.wf_aggr_status_expr_, | ||||
|                                                           need_sort, | ||||
|                                                           prefix_pos, | ||||
|                                                           NULL))) { | ||||
|                                                           NULL, | ||||
|                                                           win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL))) { | ||||
|       LOG_WARN("failed to create push down hash dist window function", K(ret)); | ||||
|     } else if (OB_FAIL(all_plans.push_back(CandidatePlan(normal_sort_top)))) { | ||||
|       LOG_WARN("failed to push back", K(ret)); | ||||
| @ -6222,6 +6304,9 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|   if (OB_SUCC(ret) && need_hash_sort) { | ||||
|     ObLogicalOperator *hash_sort_top= top; | ||||
|     OrderItem hash_sortkey; | ||||
|     bool use_part_topn = win_func_helper.enable_topn_ | ||||
|                          && prefix_pos == 0 | ||||
|                          && NULL != win_func_helper.topn_const_; | ||||
|     if (OB_FAIL(create_hash_sortkey(part_cnt, sort_keys, hash_sortkey))) { | ||||
|       LOG_WARN("failed to create hash sort key", K(ret), K(part_cnt), K(sort_keys)); | ||||
|     } else if (!need_pushdown && | ||||
| @ -6231,7 +6316,11 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|                                                         sort_keys, | ||||
|                                                         need_sort, | ||||
|                                                         prefix_pos, | ||||
|                                                         &hash_sortkey))) { | ||||
|                                                         &hash_sortkey, | ||||
|                                                         use_part_topn ? win_func_helper.topn_const_ : NULL, | ||||
|                                                         use_part_topn ? win_func_helper.is_fetch_with_ties_ : false, | ||||
|                                                         win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL, | ||||
|                                                         use_part_topn ? win_func_helper.origin_sort_card_ : 0))) { | ||||
|       LOG_WARN("failed to create normal hash dist window function", K(ret)); | ||||
|     } else if (need_pushdown && | ||||
|                OB_FAIL(create_pushdown_hash_dist_win_func(hash_sort_top, | ||||
| @ -6241,7 +6330,8 @@ int ObSelectLogPlan::create_hash_dist_win_func(ObLogicalOperator *top, | ||||
|                                                         win_func_helper.wf_aggr_status_expr_, | ||||
|                                                         need_sort, | ||||
|                                                         prefix_pos, | ||||
|                                                         &hash_sortkey))) { | ||||
|                                                         &hash_sortkey, | ||||
|                                                         win_func_helper.need_qualify_filter_ ? &win_func_helper.qualify_filters_ : NULL))) { | ||||
|       LOG_WARN("failed to create push down hash dist window function", K(ret)); | ||||
|     } else if (OB_FAIL(all_plans.push_back(CandidatePlan(hash_sort_top)))) { | ||||
|       LOG_WARN("failed to push back", K(ret)); | ||||
| @ -6256,7 +6346,11 @@ int ObSelectLogPlan::create_normal_hash_dist_win_func(ObLogicalOperator *&top, | ||||
|                                                       const ObIArray<OrderItem> &sort_keys, | ||||
|                                                       const int64_t need_sort, | ||||
|                                                       const int64_t prefix_pos, | ||||
|                                                       OrderItem *hash_sortkey) | ||||
|                                                       OrderItem *hash_sortkey, | ||||
|                                                       ObRawExpr *topn_const, | ||||
|                                                       bool is_fetch_with_ties, | ||||
|                                                       const ObIArray<ObRawExpr*> *qualify_filters, | ||||
|                                                       double origin_sort_card) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   ObExchangeInfo exch_info; | ||||
| @ -6270,8 +6364,8 @@ int ObSelectLogPlan::create_normal_hash_dist_win_func(ObLogicalOperator *&top, | ||||
|                                                       need_sort, | ||||
|                                                       prefix_pos, | ||||
|                                                       top->get_is_local_order(), | ||||
|                                                       NULL, /* topn_expr */ | ||||
|                                                       false, /* is_fetch_with_ties */ | ||||
|                                                       topn_const, /* topn_expr */ | ||||
|                                                       is_fetch_with_ties, /* is_fetch_with_ties */ | ||||
|                                                       hash_sortkey))) { | ||||
|     LOG_WARN("failed to allocate sort and exchange as top", K(ret)); | ||||
|   } else if (OB_FAIL(allocate_window_function_as_top(WinDistAlgo::WIN_DIST_HASH, | ||||
| @ -6279,8 +6373,11 @@ int ObSelectLogPlan::create_normal_hash_dist_win_func(ObLogicalOperator *&top, | ||||
|                                                     false, /* match_parallel */ | ||||
|                                                     false, /*is_partition_wise*/ | ||||
|                                                     NULL != hash_sortkey, /* use hash sort */ | ||||
|                                                     NULL != topn_const, /* use topn sort */ | ||||
|                                                     sort_keys, | ||||
|                                                     top))) { | ||||
|                                                     top, | ||||
|                                                     qualify_filters, | ||||
|                                                     origin_sort_card))) { | ||||
|     LOG_WARN("failed to allocate window function as top", K(ret)); | ||||
|   } | ||||
|   return ret; | ||||
| @ -6293,7 +6390,8 @@ int ObSelectLogPlan::create_pushdown_hash_dist_win_func(ObLogicalOperator *&top, | ||||
|                                                         ObOpPseudoColumnRawExpr *wf_aggr_status_expr, | ||||
|                                                         const int64_t need_sort, | ||||
|                                                         const int64_t prefix_pos, | ||||
|                                                         OrderItem *hash_sortkey) | ||||
|                                                         OrderItem *hash_sortkey, | ||||
|                                                         const ObIArray<ObRawExpr*> *qualify_filters) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   ObExchangeInfo exch_info; | ||||
| @ -6319,11 +6417,14 @@ int ObSelectLogPlan::create_pushdown_hash_dist_win_func(ObLogicalOperator *&top, | ||||
|                                                      false, /* match_parallel */ | ||||
|                                                      false, /* is_partition_wise */ | ||||
|                                                      NULL != hash_sortkey, /* use hash sort */ | ||||
|                                                      false, /* use hash topn sort */ | ||||
|                                                      ObLogWindowFunction::WindowFunctionRoleType::PARTICIPATOR, | ||||
|                                                      sort_keys, | ||||
|                                                      range_dist_keys_cnt, | ||||
|                                                      range_dist_pby_prefix, | ||||
|                                                      top, | ||||
|                                                      NULL, | ||||
|                                                      0.0, | ||||
|                                                      wf_aggr_status_expr, | ||||
|                                                      &pushdown_info))) { | ||||
|     LOG_WARN("failed to allocate window function as top", K(ret)); | ||||
| @ -6348,11 +6449,14 @@ int ObSelectLogPlan::create_pushdown_hash_dist_win_func(ObLogicalOperator *&top, | ||||
|                                                      false, /* match_parallel */ | ||||
|                                                      false, /* is_partition_wise */ | ||||
|                                                      NULL != hash_sortkey, /* use hash sort */ | ||||
|                                                      false, /* use hash topn sort */ | ||||
|                                                      ObLogWindowFunction::WindowFunctionRoleType::CONSOLIDATOR, | ||||
|                                                      sort_keys, | ||||
|                                                      range_dist_keys_cnt, | ||||
|                                                      range_dist_pby_prefix, | ||||
|                                                      top, | ||||
|                                                      qualify_filters, | ||||
|                                                      0.0, | ||||
|                                                      wf_aggr_status_expr, | ||||
|                                                      &pushdown_info))) { | ||||
|     LOG_WARN("failed to allocate window function as top", K(ret)); | ||||
| @ -6493,6 +6597,33 @@ int ObSelectLogPlan::check_wf_range_dist_supported(ObWinFunRawExpr *win_expr, | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObSelectLogPlan::check_wf_part_topn_supported(const common::ObIArray<ObWinFunRawExpr *> &winfunc_exprs, | ||||
|                                                   const ObIArray<ObRawExpr*> &partition_exprs, | ||||
|                                                   bool &can_wf_topn) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   int64_t part_cnt = partition_exprs.count(); | ||||
|   can_wf_topn = true; | ||||
|   for (int64 i = 0; OB_SUCC(ret) && can_wf_topn && i < winfunc_exprs.count(); ++i) { | ||||
|     ObWinFunRawExpr *win_expr = winfunc_exprs.at(i); | ||||
|     if (OB_ISNULL(win_expr)) { | ||||
|       ret = OB_ERR_UNEXPECTED; | ||||
|       LOG_WARN("get unexpected null", K(ret)); | ||||
|     } else if (win_expr->get_partition_exprs().count() != part_cnt) { | ||||
|       can_wf_topn = false; | ||||
|     } else if (win_expr->get_upper().type_ != BoundType::BOUND_UNBOUNDED | ||||
|               || win_expr->get_lower().type_ != BoundType::BOUND_UNBOUNDED) { | ||||
|       can_wf_topn = false; | ||||
|     } else { | ||||
|       ObItemType wf_type = win_expr->get_func_type(); | ||||
|       can_wf_topn = T_WIN_FUN_ROW_NUMBER == wf_type | ||||
|                     || T_WIN_FUN_RANK == wf_type | ||||
|                     || T_WIN_FUN_DENSE_RANK == wf_type; | ||||
|     } | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObSelectLogPlan::check_wf_pushdown_supported(ObWinFunRawExpr *win_expr, | ||||
|                                                  bool &can_wf_pushdown) | ||||
| { | ||||
| @ -6534,6 +6665,112 @@ int ObSelectLogPlan::check_wf_pushdown_supported(ObWinFunRawExpr *win_expr, | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| //topn option should be inited after sort keys are inited | ||||
| int ObSelectLogPlan::init_wf_topn_option(WinFuncOpHelper &win_func_helper, bool wf_topn_hint) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   const ObIArray<ObWinFunRawExpr *> &winfunc_exprs = win_func_helper.ordered_win_func_exprs_; | ||||
|   const ObIArray<ObRawExpr *> &filter_exprs = win_func_helper.qualify_filters_; | ||||
|   win_func_helper.is_fetch_with_ties_ = false; | ||||
|   win_func_helper.topn_const_ = NULL; | ||||
|   if (winfunc_exprs.count() != win_func_helper.all_win_func_exprs_.count()) { | ||||
|     //not only one group | ||||
|      win_func_helper.enable_topn_ = false; | ||||
|   } else if (wf_topn_hint) { | ||||
|     win_func_helper.enable_topn_ = true; | ||||
|   } else if (OB_ISNULL(get_optimizer_context().get_session_info())) { | ||||
|     ret = OB_ERR_UNEXPECTED; | ||||
|     LOG_WARN("unexpected null", K(ret), K(get_optimizer_context().get_session_info())); | ||||
|   } else { | ||||
|     win_func_helper.enable_topn_ = get_optimizer_context().get_session_info()->is_qualify_filter_enabled(); | ||||
|   } | ||||
|   if (OB_FAIL(ret) || !win_func_helper.enable_topn_) { | ||||
|     //do nothing | ||||
|   } else if (check_wf_part_topn_supported(winfunc_exprs, | ||||
|                                           win_func_helper.partition_exprs_, | ||||
|                                           win_func_helper.enable_topn_)) { | ||||
|     LOG_WARN("check partition topn supported failed", K(ret)); | ||||
|   } else if (win_func_helper.enable_topn_) { | ||||
|     for (int64_t i = 0; OB_SUCC(ret) && NULL == win_func_helper.topn_const_ && i < filter_exprs.count(); ++i) { | ||||
|       ObRawExpr *const_expr = NULL; | ||||
|       bool ties_flag = false; | ||||
|       bool is_topn_filter = false; | ||||
|       ObWinFunRawExpr *win_expr = NULL; | ||||
|       if (OB_FAIL(ObTransformUtils::is_winfunc_topn_filter(winfunc_exprs, filter_exprs.at(i), is_topn_filter, | ||||
|                                                             const_expr, ties_flag, win_expr))) { | ||||
|         LOG_WARN("check whether the filter is a winfunc topn filter failed", K(ret)); | ||||
|       } else if (is_topn_filter) { | ||||
|         //order by must be the same as the sort keys | ||||
|         if (OB_ISNULL(win_expr)) { | ||||
|           ret = OB_ERR_UNEXPECTED; | ||||
|           LOG_WARN("unexpected null", K(ret)); | ||||
|         } else { | ||||
|           const common::ObIArray<OrderItem> &order_items = win_expr->get_order_items(); | ||||
|           if (order_items.count() + win_func_helper.part_cnt_ != win_func_helper.sort_keys_.count()) { | ||||
|             is_topn_filter = false; | ||||
|           } else { | ||||
|             for (int64_t j = 0; is_topn_filter && j < order_items.count(); ++j) { | ||||
|               if (order_items.at(j) != win_func_helper.sort_keys_.at(j + win_func_helper.part_cnt_)) { | ||||
|                 is_topn_filter = false; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           if (is_topn_filter) { | ||||
|             win_func_helper.topn_const_ = const_expr; | ||||
|             win_func_helper.is_fetch_with_ties_ = ties_flag; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (OB_SUCC(ret) | ||||
|         && NULL == win_func_helper.topn_const_) { | ||||
|       win_func_helper.enable_topn_ = false; | ||||
|     } | ||||
|   } | ||||
|   if (OB_SUCC(ret) | ||||
|       && NULL != win_func_helper.topn_const_ | ||||
|       && !ob_is_integer_type(win_func_helper.topn_const_->get_result_type().get_type())) { | ||||
|     //cast topn expr to int | ||||
|     ObRawExpr *topn_with_cast = NULL; | ||||
|     ObRawExpr *topn_without_cast = NULL; | ||||
|     ObExprResType res_type; | ||||
|     bool need_cast = false; | ||||
|     bool ignore_err = false; | ||||
|     const ObExprResType &src_type = win_func_helper.topn_const_->get_result_type(); | ||||
|     res_type.set_int(); | ||||
|     res_type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].precision_); | ||||
|     res_type.set_scale(DEFAULT_SCALE_FOR_INTEGER); | ||||
|     if (OB_FAIL(ObRawExprUtils::check_need_cast_expr(src_type, res_type, need_cast, ignore_err))) { | ||||
|       LOG_WARN("failed to check need cast expr", K(ret), K(src_type), K(res_type)); | ||||
|     } else if (!need_cast) { | ||||
|       // do nothing | ||||
|     } else if (OB_ISNULL((topn_without_cast = ObRawExprUtils::skip_implicit_cast(win_func_helper.topn_const_)))) { | ||||
|       ret = OB_ERR_UNEXPECTED; | ||||
|       LOG_WARN("unexpected null", K(ret)); | ||||
|     } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(&get_optimizer_context().get_expr_factory(), | ||||
|                                                                get_optimizer_context().get_session_info(), | ||||
|                                                                *topn_without_cast, | ||||
|                                                                res_type, | ||||
|                                                                topn_with_cast))) { | ||||
|       LOG_WARN("create cast expr for stmt failed", K(ret)); | ||||
|     } else { | ||||
|       win_func_helper.topn_const_ = topn_with_cast; | ||||
|     } | ||||
|   } | ||||
|   if (OB_SUCC(ret) && win_func_helper.enable_topn_) { | ||||
|     ObLogicalOperator *best_plan = NULL; | ||||
|     if (OB_FAIL(candidates_.get_best_plan(best_plan))) { | ||||
|       LOG_WARN("failed to get best plan", K(ret)); | ||||
|     } else if (OB_ISNULL(best_plan)) { | ||||
|       ret = OB_ERR_UNEXPECTED; | ||||
|       LOG_WARN("get unexpected null", K(ret)); | ||||
|     } else { | ||||
|       win_func_helper.origin_sort_card_ = best_plan->get_card(); | ||||
|     } | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObSelectLogPlan::get_pushdown_window_function_exchange_info( | ||||
|     const ObIArray<ObWinFunRawExpr *> &win_exprs, | ||||
|     ObLogicalOperator *op, | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 yinyj17
					yinyj17