[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:
yinyj17
2023-12-16 14:12:43 +00:00
committed by ant-ob-hengtang
parent 438a70b2b8
commit 37fe7ce4eb
50 changed files with 3205 additions and 1059 deletions

View File

@ -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,