[CP] adjust merge into partition prune constraint

This commit is contained in:
chimyue
2023-07-13 14:42:17 +00:00
committed by ob-robot
parent 59a7f93a3f
commit a61043f93b
9 changed files with 150 additions and 96 deletions

View File

@ -202,9 +202,10 @@ int ObMergeLogPlan::create_merge_plans(ObIArray<CandidatePlan> &candi_plans,
int ret = OB_SUCCESS;
ObExchangeInfo exch_info;
CandidatePlan candi_plan;
ObSEArray<ObPCParamEqualInfo, 1> equal_infos;
ObSEArray<std::pair<ObRawExpr*, ObRawExpr*>, 1> equal_pairs;
bool is_multi_part_dml = false;
for (int64_t i = 0; OB_SUCC(ret) && i < candi_plans.count(); i++) {
equal_pairs.reuse();
candi_plan = candi_plans.at(i);
is_multi_part_dml = force_multi_part;
if (OB_ISNULL(candi_plan.plan_tree_)) {
@ -215,7 +216,7 @@ int ObMergeLogPlan::create_merge_plans(ObIArray<CandidatePlan> &candi_plans,
insert_table_part,
insert_sharding,
is_multi_part_dml,
equal_infos))) {
equal_pairs))) {
LOG_WARN("failed to check need multi-partition dml", K(ret));
} else if (is_multi_part_dml && force_no_multi_part) {
/*do nothing*/
@ -224,7 +225,7 @@ int ObMergeLogPlan::create_merge_plans(ObIArray<CandidatePlan> &candi_plans,
&& OB_FAIL(allocate_exchange_as_top(candi_plan.plan_tree_, exch_info))) {
LOG_WARN("failed to allocate exchange as top", K(ret));
} else if (OB_FAIL(allocate_merge_as_top(candi_plan.plan_tree_, insert_table_part,
is_multi_part_dml, &equal_infos))) {
is_multi_part_dml, &equal_pairs))) {
LOG_WARN("failed to allocate merge as top", K(ret));
} else if (OB_FAIL(merge_plans.push_back(candi_plan))) {
LOG_WARN("failed to push back", K(ret));
@ -367,7 +368,7 @@ int ObMergeLogPlan::candi_allocate_subplan_filter_for_merge()
int ObMergeLogPlan::allocate_merge_as_top(ObLogicalOperator *&top,
ObTablePartitionInfo *table_partition_info,
bool is_multi_part_dml,
const ObIArray<ObPCParamEqualInfo> *equal_infos)
const ObIArray<std::pair<ObRawExpr*, ObRawExpr*>> *equal_pairs)
{
int ret = OB_SUCCESS;
ObLogMerge *merge_op = NULL;
@ -387,8 +388,8 @@ int ObMergeLogPlan::allocate_merge_as_top(ObLogicalOperator *&top,
merge_op->set_child(ObLogicalOperator::first_child, top);
merge_op->set_is_multi_part_dml(is_multi_part_dml);
merge_op->set_table_partition_info(table_partition_info);
if (NULL != equal_infos && OB_FAIL(merge_op->set_equal_infos(*equal_infos))) {
LOG_WARN("failed to set equal infos", K(ret));
if (NULL != equal_pairs && OB_FAIL(merge_op->set_equal_pairs(*equal_pairs))) {
LOG_WARN("failed to set equal pairs", K(ret));
} else if (OB_FAIL(merge_op->compute_property())) {
LOG_WARN("failed to compute property", K(ret));
} else {
@ -408,34 +409,44 @@ int ObMergeLogPlan::check_merge_need_multi_partition_dml(ObLogicalOperator &top,
ObTablePartitionInfo *insert_table_partition,
ObShardingInfo *insert_sharding,
bool &is_multi_part_dml,
ObIArray<ObPCParamEqualInfo> &equal_infos)
ObIArray<std::pair<ObRawExpr*, ObRawExpr*>> &equal_pairs)
{
int ret = OB_SUCCESS;
is_multi_part_dml = false;
equal_infos.reset();
equal_pairs.reset();
bool is_one_part_table = false;
bool is_partition_wise = false;
bool is_basic = false;
const ObMergeStmt *merge_stmt = NULL;
bool is_result_local = false;
if (OB_ISNULL(merge_stmt = get_stmt())) {
ObShardingInfo *update_sharding = NULL;
if (OB_ISNULL(merge_stmt = get_stmt()) ||
OB_UNLIKELY(index_dml_infos_.empty()) || OB_ISNULL(index_dml_infos_.at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(merge_stmt));
} else if (OB_FAIL(check_need_multi_partition_dml(*merge_stmt, // zhanyue todo:will call basic function, need check it
top,
index_dml_infos_,
is_multi_part_dml,
is_result_local))) {
LOG_WARN("failed to check need multi-partition dml", K(ret));
LOG_WARN("unexpected params", K(ret), K(merge_stmt), K(index_dml_infos_));
} else if (OB_FAIL(check_stmt_need_multi_partition_dml(*merge_stmt, index_dml_infos_, is_multi_part_dml))) {
LOG_WARN("failed to check stmt need multi partition dml", K(ret));
} else if (is_multi_part_dml) {
/*do nothing*/
} else if (OB_FAIL(check_merge_stmt_need_multi_partition_dml(is_multi_part_dml, is_one_part_table))) {
LOG_WARN("failed to check need multi-partition dml", K(ret));
} else if (is_multi_part_dml) {
/*do nothing*/
} else if (OB_FAIL(check_location_need_multi_partition_dml(top,
index_dml_infos_.at(0)->loc_table_id_,
is_multi_part_dml,
is_result_local,
update_sharding))) {
LOG_WARN("failed to check whether location need multi-partition dml", K(ret));
} else if (is_multi_part_dml) {
/*do nothing*/
} else if (!merge_stmt->has_insert_clause() || is_one_part_table) {
is_multi_part_dml = false;
} else if (OB_FAIL(check_update_insert_sharding_basic(top, insert_sharding, is_basic, equal_infos))) {
} else if (OB_FAIL(check_update_insert_sharding_basic(top,
insert_sharding,
update_sharding,
is_basic,
equal_pairs))) {
LOG_WARN("failed to check update insert sharding basic", K(ret));
} else if (is_basic) {
is_multi_part_dml = false;
@ -450,21 +461,23 @@ int ObMergeLogPlan::check_merge_need_multi_partition_dml(ObLogicalOperator &top,
if (OB_SUCC(ret)) {
LOG_TRACE("succeed to check merge_stmt need multi-partition-dml", K(is_multi_part_dml),
K(is_partition_wise), K(equal_infos));
K(is_partition_wise), K(equal_pairs));
}
return ret;
}
int ObMergeLogPlan::check_update_insert_sharding_basic(ObLogicalOperator &top,
ObShardingInfo *insert_sharding,
ObShardingInfo *update_sharding,
bool &is_basic,
ObIArray<ObPCParamEqualInfo> &equal_infos)
ObIArray<std::pair<ObRawExpr*, ObRawExpr*>> &equal_pairs)
{
int ret = OB_SUCCESS;
is_basic = false;
bool can_gen_cons = false;
ObShardingInfo *update_sharding = top.get_strong_sharding();
ObSEArray<ObShardingInfo*, 2> input_sharding;
bool is_sharding_basic = false;
bool is_match_same_partition = false;
if (NULL == insert_sharding || NULL == update_sharding) {
/* do nothing */
} else if (OB_FAIL(input_sharding.push_back(insert_sharding))
@ -472,21 +485,23 @@ int ObMergeLogPlan::check_update_insert_sharding_basic(ObLogicalOperator &top,
LOG_WARN("failed to push back sharding info", K(ret));
} else if (OB_FAIL(ObOptimizerUtil::check_basic_sharding_info(get_optimizer_context().get_local_server_addr(),
input_sharding,
is_basic))) {
is_sharding_basic))) {
LOG_WARN("failed to check basic sharding info", K(ret));
} else if (!is_basic) {
} else if (!is_sharding_basic) {
/* do nothing */
} else if (!match_same_partition(*insert_sharding, *update_sharding)) {
} else if (false == (is_match_same_partition = match_same_partition(*insert_sharding, *update_sharding))) {
/* insert_sharding and update_sharding match basic,
but the partition is different, need multi part merge */
is_basic = false;
} else if (OB_FAIL(generate_equal_constraint(top, *insert_sharding, can_gen_cons, equal_infos))) {
} else if (OB_FAIL(generate_equal_constraint(top, *insert_sharding, can_gen_cons, equal_pairs))) {
LOG_WARN("failed to generate equal constraint", K(ret));
} else if (can_gen_cons) {
is_basic = true;
} else {
is_basic = false;
}
LOG_TRACE("finish check update insert sharding basic", K(is_basic), K(is_sharding_basic),
K(is_match_same_partition), K(can_gen_cons), KPC(insert_sharding), KPC(update_sharding));
return ret;
}
@ -513,21 +528,20 @@ bool ObMergeLogPlan::match_same_partition(const ObShardingInfo &l_sharding_info,
int ObMergeLogPlan::generate_equal_constraint(ObLogicalOperator &top,
ObShardingInfo &insert_sharding,
bool &can_gen_cons,
ObIArray<ObPCParamEqualInfo> &equal_infos)
ObIArray<std::pair<ObRawExpr*, ObRawExpr*>> &equal_pairs)
{
int ret = OB_SUCCESS;
equal_infos.reset();
equal_pairs.reset();
can_gen_cons = false;
ObLogTableScan *target_table_scan = NULL;
ObSEArray<ObRawExpr*, 4> left_part_keys;
ObSEArray<ObRawExpr*, 4> right_part_keys;
ObSEArray<ObRawExpr*, 4> right_conds;
ObQueryCtx *query_ctx = NULL;
const ObMergeStmt *stmt = NULL;
const TableItem *target_table = NULL;
if (OB_ISNULL(stmt = get_stmt()) || OB_ISNULL(query_ctx = get_stmt()->get_query_ctx())) {
if (OB_ISNULL(stmt = get_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(stmt), K(query_ctx));
LOG_WARN("get unexpected null", K(ret), K(stmt));
} else if (OB_ISNULL(target_table = stmt->get_table_item_by_id(stmt->get_target_table_id()))) {
LOG_WARN("failed to get target table", K(ret));
} else if (OB_FAIL(get_target_table_scan(target_table->get_base_table_item().table_id_,
@ -547,57 +561,77 @@ int ObMergeLogPlan::generate_equal_constraint(ObLogicalOperator &top,
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected part key size", K(ret), K(left_part_keys), K(right_part_keys));
} else {
ObSEArray<ObConstRawExpr*, 4> l_const_exprs;
ObSEArray<ObConstRawExpr*, 4> r_const_exprs;
ObSEArray<ObRawExpr*, 4> l_const_exprs;
ObSEArray<ObRawExpr*, 4> r_const_exprs;
const ObIArray<ObRawExpr*> &left_conds = stmt->get_sharding_conditions();
bool has_equal = true;
can_gen_cons = true;
ObStmtCompareContext context;
context.init(&query_ctx->calculable_items_);
for (int64_t i = 0; OB_SUCC(ret) && has_equal && i < left_part_keys.count(); ++i) {
if (OB_FAIL(get_const_expr_values(left_part_keys.at(i), left_conds, l_const_exprs))) {
if (OB_FAIL(get_const_expr_values(left_part_keys.at(i),
left_conds,
l_const_exprs))) {
LOG_WARN("failed to get const expr values", K(ret));
} else if (OB_FAIL(get_const_expr_values(right_part_keys.at(i),
right_conds,
r_const_exprs))) {
LOG_WARN("failed to get const expr values", K(ret));
} else if (ObOptimizerUtil::overlap(l_const_exprs, r_const_exprs)) {
/* exists shared exprs in l_const_exprs and r_const_exprs, need not add constrain */
} else if (OB_FAIL(has_equal_values(l_const_exprs,
r_const_exprs,
context,
has_equal,
equal_infos))) {
equal_pairs))) {
LOG_WARN("failed to check has equal values", K(ret));
}
}
if (OB_SUCC(ret) && !has_equal) {
equal_infos.reset();
equal_pairs.reset();
can_gen_cons = false;
}
LOG_TRACE("finish generate equal constraint", K(can_gen_cons), K(equal_pairs),
K(left_part_keys), K(left_conds), K(right_part_keys), K(right_conds));
}
return ret;
}
int ObMergeLogPlan::has_equal_values(const ObIArray<ObConstRawExpr*> &l_const_exprs,
const ObIArray<ObConstRawExpr*> &r_const_exprs,
ObStmtCompareContext &context,
int ObMergeLogPlan::has_equal_values(const ObIArray<ObRawExpr*> &l_const_exprs,
const ObIArray<ObRawExpr*> &r_const_exprs,
bool &has_equal,
ObIArray<ObPCParamEqualInfo> &equal_infos)
ObIArray<std::pair<ObRawExpr*, ObRawExpr*>> &equal_pairs)
{
int ret = OB_SUCCESS;
has_equal = false;
ObObj l_value;
ObObj r_value;
bool is_valid = false;
ObOptimizerContext &opt_ctx = get_optimizer_context();
int eq_cmp = 0;
for (int64_t i = 0; OB_SUCC(ret) && !has_equal && i < l_const_exprs.count(); ++i) {
if (OB_ISNULL(l_const_exprs.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(i), K(l_const_exprs));
}
for (int64_t j = 0; OB_SUCC(ret) && !has_equal && j < r_const_exprs.count(); ++j) {
context.equal_param_info_.reset();
if (OB_ISNULL(r_const_exprs.at(j))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(j), K(r_const_exprs));
} else if (l_const_exprs.at(i)->same_as(*r_const_exprs.at(j), &context)) {
if (OB_FAIL(append(equal_infos, context.equal_param_info_))) {
LOG_WARN("failed to append equal infos", K(ret));
if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(opt_ctx.get_exec_ctx(),
l_const_exprs.at(i),
l_value,
is_valid,
opt_ctx.get_allocator()))) {
LOG_WARN("failed to calc const or calculable expr", K(ret));
} else if (!is_valid) {
/* do nothing */
} else {
for (int64_t j = 0; OB_SUCC(ret) && !has_equal && j < r_const_exprs.count(); ++j) {
if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(opt_ctx.get_exec_ctx(),
r_const_exprs.at(j),
r_value,
is_valid,
opt_ctx.get_allocator()))) {
// Since calculated expr is cached in exec_ctx when call calc_const_or_calculable_expr,
// we can call calc_const_or_calculable_expr repeatedly for the same expr.
LOG_WARN("failed to calc const or calculable expr", K(ret));
} else if (!is_valid) {
/* do nothing */
} else if (OB_UNLIKELY(OB_SUCCESS != l_value.compare(r_value, eq_cmp))
|| 0 != eq_cmp) {
/* do nothing */
} else if (OB_FAIL(equal_pairs.push_back(std::pair<ObRawExpr*, ObRawExpr*>(l_const_exprs.at(i), r_const_exprs.at(j))))) {
LOG_WARN("failed to push back", K(ret));
} else {
has_equal = true;
}
@ -608,8 +642,8 @@ int ObMergeLogPlan::has_equal_values(const ObIArray<ObConstRawExpr*> &l_const_ex
}
int ObMergeLogPlan::get_const_expr_values(const ObRawExpr *part_expr,
const ObIArray<ObRawExpr*> &conds,
ObIArray<ObConstRawExpr*> &const_exprs)
const ObIArray<ObRawExpr*> &conds,
ObIArray<ObRawExpr*> &const_exprs)
{
int ret = OB_SUCCESS;
const_exprs.reuse();
@ -620,7 +654,7 @@ int ObMergeLogPlan::get_const_expr_values(const ObRawExpr *part_expr,
/* do nothing */
} else {
ObRawExpr *cur_expr = NULL;
ObConstRawExpr *const_expr = NULL;
ObRawExpr *const_expr = NULL;
ObRawExpr *param_1 = NULL;
ObRawExpr *param_2 = NULL;
bool is_const = false;
@ -639,10 +673,10 @@ int ObMergeLogPlan::get_const_expr_values(const ObRawExpr *part_expr,
LOG_WARN("failed to get expr without lossless cast", K(ret));
} else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(param_2, param_2))) {
LOG_WARN("failed to get expr without lossless cast", K(ret));
} else if (part_expr == param_1 && param_2->is_const_raw_expr()) {
const_expr = static_cast<ObConstRawExpr*>(param_2);
} else if (part_expr == param_2 && param_1->is_const_raw_expr()) {
const_expr = static_cast<ObConstRawExpr*>(param_1);
} else if (part_expr == param_1 && param_2->is_const_expr()) {
const_expr = param_2;
} else if (part_expr == param_2 && param_1->is_const_expr()) {
const_expr = param_1;
}
if (NULL != const_expr && ob_is_valid_obj_tc(const_expr->get_type_class())) {
@ -710,8 +744,7 @@ int ObMergeLogPlan::check_update_insert_sharding_partition_wise(ObLogicalOperato
LOG_WARN("failed to append exprs", K(ret));
} else if (OB_FAIL(stmt->get_value_exprs(source_exprs))) {
LOG_WARN("failed to get value exprs", K(ret));
}
else if (OB_UNLIKELY(target_exprs.count() != source_exprs.count())) {
} else if (OB_UNLIKELY(target_exprs.count() != source_exprs.count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected exprs count", K(ret), K(target_exprs), K(source_exprs));
} else {