diff --git a/src/sql/optimizer/ob_insert_log_plan.cpp b/src/sql/optimizer/ob_insert_log_plan.cpp index 1293398749..5b1aa77d68 100644 --- a/src/sql/optimizer/ob_insert_log_plan.cpp +++ b/src/sql/optimizer/ob_insert_log_plan.cpp @@ -423,7 +423,7 @@ int ObInsertLogPlan::candi_allocate_insert(OSGShareInfo *osg_info) int ret = OB_SUCCESS; ObConstRawExpr *lock_row_flag_expr = NULL; ObTablePartitionInfo *insert_table_part = NULL; - ObShardingInfo *insert_sharding = NULL; + ObShardingInfo *insert_table_sharding = NULL; ObSEArray candi_plans; ObSEArray insert_plans; const bool force_no_multi_part = get_log_plan_hint().no_use_distributed_dml(); @@ -434,14 +434,14 @@ int ObInsertLogPlan::candi_allocate_insert(OSGShareInfo *osg_info) if (OB_FAIL(build_lock_row_flag_expr(lock_row_flag_expr))) { LOG_WARN("failed to build lock row flag expr", K(ret)); } else if (OB_FAIL(calculate_insert_table_location_and_sharding(insert_table_part, - insert_sharding))) { + insert_table_sharding))) { LOG_WARN("failed to calculate insert table location and sharding", K(ret)); } else if (OB_FAIL(get_minimal_cost_candidates(candidates_.candidate_plans_, candi_plans))) { LOG_WARN("failed to get minimal cost candidates", K(ret)); } else if (OB_FAIL(create_insert_plans(candi_plans, insert_table_part, - insert_sharding, + insert_table_sharding, lock_row_flag_expr, force_no_multi_part, force_multi_part, @@ -453,7 +453,7 @@ int ObInsertLogPlan::candi_allocate_insert(OSGShareInfo *osg_info) } else if (OB_FAIL(get_log_plan_hint().check_status())) { LOG_WARN("failed to generate plans with hint", K(ret)); } else if (OB_FAIL(create_insert_plans(candi_plans, insert_table_part, - insert_sharding, + insert_table_sharding, lock_row_flag_expr, false, false, insert_plans, @@ -496,7 +496,7 @@ int ObInsertLogPlan::build_lock_row_flag_expr(ObConstRawExpr *&lock_row_flag_exp int ObInsertLogPlan::create_insert_plans(ObIArray &candi_plans, ObTablePartitionInfo *insert_table_part, - ObShardingInfo *insert_sharding, + ObShardingInfo *insert_table_sharding, ObConstRawExpr *lock_row_flag_expr, const bool force_no_multi_part, const bool force_multi_part, @@ -507,32 +507,64 @@ int ObInsertLogPlan::create_insert_plans(ObIArray &candi_plans, ObExchangeInfo exch_info; bool is_multi_part_dml = false; CandidatePlan candi_plan; + int64_t inherit_sharding_index = OB_INVALID_INDEX; + ObShardingInfo *insert_op_sharding = NULL; + ObSEArray input_shardings; + int64_t distributed_methods = DIST_BASIC_METHOD | DIST_PARTITION_WISE | DIST_PULL_TO_LOCAL; for (int64_t i = 0; OB_SUCC(ret) && i < candi_plans.count(); i++) { candi_plan = candi_plans.at(i); is_multi_part_dml = force_multi_part; + input_shardings.reuse(); + insert_op_sharding = NULL; if (OB_ISNULL(candi_plan.plan_tree_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); - } else if (!force_multi_part && - OB_FAIL(check_insert_need_multi_partition_dml(*candi_plan.plan_tree_, - insert_table_part, - insert_sharding, - is_multi_part_dml))) { - LOG_WARN("failed to check need multi-partition dml", K(ret)); - } else if (is_multi_part_dml && force_no_multi_part) { + } else if (OB_FAIL(get_best_insert_dist_method(*candi_plan.plan_tree_, + insert_table_part, + insert_table_sharding, + force_no_multi_part, + force_multi_part, + distributed_methods, + is_multi_part_dml))) { + LOG_WARN("failed to get best insert plan method", K(ret)); + } else if (0 == distributed_methods) { /*do nothing*/ } else if (osg_info != NULL && OB_FAIL(allocate_optimizer_stats_gathering_as_top(candi_plan.plan_tree_, *osg_info))) { LOG_WARN("failed to allocate sequence as top", K(ret)); - } else if (candi_plan.plan_tree_->is_sharding() && - (is_multi_part_dml || insert_sharding->is_local()) && - OB_FAIL(allocate_exchange_as_top(candi_plan.plan_tree_, exch_info))) { - LOG_WARN("failed to allocate exchange as top", K(ret)); + } else if (DIST_PULL_TO_LOCAL == distributed_methods) { + if (OB_FAIL(allocate_exchange_as_top(candi_plan.plan_tree_, exch_info))) { + LOG_WARN("failed to allocate exchange as top", K(ret)); + } else { + insert_op_sharding = get_optimizer_context().get_local_sharding(); + } + } else if (DIST_BASIC_METHOD == distributed_methods) { + if (OB_FAIL(input_shardings.push_back(candi_plan.plan_tree_->get_strong_sharding()))) { + LOG_WARN("failed to push back sharding", K(ret)); + } else if (OB_FAIL(input_shardings.push_back(is_multi_part_dml ? + get_optimizer_context().get_local_sharding() : + insert_table_sharding))) { + LOG_WARN("failed to push back sharding", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::compute_basic_sharding_info( + get_optimizer_context().get_local_server_addr(), + input_shardings, + get_optimizer_context().get_allocator(), + insert_op_sharding, + inherit_sharding_index))) { + LOG_WARN("failed to compute basic sharding info", K(ret)); + } + } else if (DIST_PARTITION_WISE == distributed_methods) { + insert_op_sharding = candi_plan.plan_tree_->get_strong_sharding(); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid method", K(distributed_methods), K(ret)); + } + if (OB_FAIL(ret) || OB_ISNULL(insert_op_sharding)) { } else if (OB_FAIL(allocate_insert_as_top(candi_plan.plan_tree_, lock_row_flag_expr, insert_table_part, - insert_sharding, + insert_op_sharding, is_multi_part_dml))) { LOG_WARN("failed to allocate insert as top", K(ret)); } else if (OB_FAIL(insert_plans.push_back(candi_plan))) { @@ -545,7 +577,7 @@ int ObInsertLogPlan::create_insert_plans(ObIArray &candi_plans, int ObInsertLogPlan::allocate_insert_as_top(ObLogicalOperator *&top, ObRawExpr *lock_row_flag_expr, ObTablePartitionInfo *table_partition_info, - ObShardingInfo *insert_sharding, + ObShardingInfo *insert_op_sharding, bool is_multi_part_dml) { int ret = OB_SUCCESS; @@ -578,9 +610,7 @@ int ObInsertLogPlan::allocate_insert_as_top(ObLogicalOperator *&top, if (OB_NOT_NULL(insert_stmt->get_table_item(0))) { insert_op->set_append_table_id(insert_stmt->get_table_item(0)->ref_id_); } - if (top->is_match_all() && !is_multi_part_dml && !insert_stmt->has_instead_of_trigger()) { - insert_op->set_strong_sharding(insert_sharding); - } + insert_op->set_strong_sharding(insert_op_sharding); if (insert_stmt->is_insert_up()) { insert_op->set_insert_up(true); } @@ -623,35 +653,85 @@ int ObInsertLogPlan::candi_allocate_pdml_insert(OSGShareInfo *osg_info) /* * for insert stmt to check whether need multi-partition dml */ -int ObInsertLogPlan::check_insert_need_multi_partition_dml(ObLogicalOperator &top, - ObTablePartitionInfo *insert_table_partition, - ObShardingInfo *insert_sharding, - bool &is_multi_part_dml) +int ObInsertLogPlan::get_best_insert_dist_method(ObLogicalOperator &top, + ObTablePartitionInfo *insert_table_partition, + ObShardingInfo *insert_table_sharding, + const bool force_no_multi_part, + const bool force_multi_part, + int64_t &distributed_methods, + bool &is_multi_part_dml) { int ret = OB_SUCCESS; is_multi_part_dml = false; - bool is_one_part_table = false; - if (OB_ISNULL(get_stmt())) { + bool is_basic = false; + bool is_partition_wise = false; + ObShardingInfo *local_sharding = get_optimizer_context().get_local_sharding(); + if (OB_ISNULL(local_sharding)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(get_stmt()), K(ret)); - } else if (OB_FAIL(check_insert_stmt_need_multi_partition_dml(is_multi_part_dml, - is_one_part_table))) { + LOG_WARN("get unexpected null", K(local_sharding), K(ret)); + } else if (OB_FAIL(check_insert_plan_need_multi_partition_dml(insert_table_partition, + insert_table_sharding, + is_multi_part_dml))) { LOG_WARN("failed to check if insert stmt need multi-partition dml", K(ret)); + } else if (is_multi_part_dml && force_no_multi_part) { + distributed_methods = 0; + } else if (OB_FALSE_IT(is_multi_part_dml |= force_multi_part)) { + //hint force use multi part dml } else if (is_multi_part_dml) { - /*do nothing*/ - } else if (OB_FAIL(check_insert_location_need_multi_partition_dml(top, - insert_table_partition, - insert_sharding, - is_one_part_table, - is_multi_part_dml))) { - LOG_WARN("failed to check if insert stmt need multi-partition dml", K(ret)); - } else { /*do nothing*/ } - + if (OB_FAIL(check_basic_sharding_for_insert_stmt(*local_sharding, + top, + is_basic))) { + LOG_WARN("failed to check basic sharding for insert stmt", K(ret)); + } else if (is_basic) { + distributed_methods = DIST_BASIC_METHOD; + OPT_TRACE("insert plan will use basic method"); + } else { + distributed_methods = DIST_PULL_TO_LOCAL; + OPT_TRACE("insert plan will use pull to local method"); + } + } else if (OB_ISNULL(insert_table_sharding)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(insert_table_sharding), K(ret)); + } else if ((distributed_methods & DIST_PARTITION_WISE) && + OB_FAIL(check_if_match_partition_wise_insert(*insert_table_sharding, + top, + is_partition_wise))) { + LOG_WARN("failed to check if match partition wise insert", K(ret)); + } else if (is_partition_wise) { + distributed_methods = DIST_PARTITION_WISE; + OPT_TRACE("insert plan will use partition wise method"); + } else if (OB_FAIL(check_basic_sharding_for_insert_stmt(*insert_table_sharding, + top, + is_basic))) { + LOG_WARN("failed to check basic sharding for insert stmt", K(ret)); + } else if (is_basic) { + distributed_methods = DIST_BASIC_METHOD; + OPT_TRACE("insert plan will use basic method"); + } else if (!insert_table_sharding->is_local() && + OB_FALSE_IT(is_multi_part_dml=true)) { + //insert into remote table, force use multi part dml + } else if (OB_FAIL(check_basic_sharding_for_insert_stmt(*local_sharding, + top, + is_basic))) { + LOG_WARN("failed to check basic sharding for insert stmt", K(ret)); + } else if (is_basic) { + distributed_methods = DIST_BASIC_METHOD; + OPT_TRACE("insert partition table force use multi part dml"); + OPT_TRACE("insert plan will use basic method"); + } else { + distributed_methods = DIST_PULL_TO_LOCAL; + OPT_TRACE("insert partition table force use multi part dml"); + OPT_TRACE("insert plan will use pull to local method"); + } + if (OB_SUCC(ret)) { + LOG_TRACE("succeed to get best insert plan", K(is_multi_part_dml), K(distributed_methods)); + } return ret; } -int ObInsertLogPlan::check_insert_stmt_need_multi_partition_dml(bool &is_multi_part_dml, - bool &is_one_part_table) +int ObInsertLogPlan::check_insert_plan_need_multi_partition_dml(ObTablePartitionInfo *insert_table_part, + ObShardingInfo *insert_table_sharding, + bool &is_multi_part_dml) { int ret = OB_SUCCESS; bool has_rand_part_key = false; @@ -664,21 +744,30 @@ int ObInsertLogPlan::check_insert_stmt_need_multi_partition_dml(bool &is_multi_p ObSQLSessionInfo *session_info = NULL; ObSEArray part_ids; is_multi_part_dml = false; - is_one_part_table = false; - if (OB_ISNULL(insert_stmt = get_stmt()) || + bool is_one_part_table = false; + if (OB_ISNULL(insert_table_part) || OB_ISNULL(insert_table_sharding)) { + //insert into values + is_multi_part_dml = true; + } else if (OB_ISNULL(insert_stmt = get_stmt()) || OB_ISNULL(schema_guard = get_optimizer_context().get_schema_guard()) || OB_ISNULL(session_info = get_optimizer_context().get_session_info())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(insert_stmt), K(schema_guard), K(session_info), K(ret)); - } else if (insert_stmt->has_instead_of_trigger() || index_dml_infos_.count() > 1 || + } else if (0 == insert_table_part->get_phy_tbl_location_info().get_partition_cnt()) { + is_multi_part_dml = true; + OPT_TRACE("insert table has no partition, force use multi part dml"); + } else if (insert_stmt->has_instead_of_trigger() || + index_dml_infos_.count() > 1 || get_optimizer_context().is_batched_multi_stmt() || //ddl sql can produce a PDML plan with PL UDF, //some PL UDF that cannot be executed in a PDML plan //will be forbidden during the execution phase optimizer_context_.contain_user_nested_sql()) { is_multi_part_dml = true; + OPT_TRACE("trigger/multi insert/batch stmt/nested sql, force use multi part dml"); } else if (!insert_stmt->value_from_select()) { is_multi_part_dml = true; + OPT_TRACE("insert into values, force use multi part dml"); } else if (OB_FAIL(schema_guard->get_table_schema(session_info->get_effective_tenant_id(), insert_stmt->get_insert_table_info().ref_table_id_, table_schema))) { @@ -687,22 +776,31 @@ int ObInsertLogPlan::check_insert_stmt_need_multi_partition_dml(bool &is_multi_p ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FALSE_IT(is_one_part_table = ObSQLUtils::is_one_part_table_can_skip_part_calc(*table_schema))) { + } else if (insert_table_sharding->is_single() && + !is_one_part_table && + insert_table_part->get_table_location().is_part_or_subpart_all_partition()) { + is_multi_part_dml = true; + OPT_TRACE("insert table has only one partition in partition level, force use multi part dml"); } else if ((insert_stmt->is_ignore() && !is_one_part_table) || (lib::is_mysql_mode() && !is_strict_mode(session_info->get_sql_mode()))) { // insert ignore,并且是分区表插入时,不能优化 // mysql non strict mode can not optimize as multi part dml is_multi_part_dml = true; + OPT_TRACE("insert partition table with ignore/mysql non strict mode, force use multi part dml"); } else if (!insert_stmt->get_insert_table_info().part_ids_.empty() && insert_stmt->value_from_select()) { is_multi_part_dml = true; + OPT_TRACE("insert partition table with ignore/mysql non strict mode, force use multi part dml"); } else if (OB_FAIL(insert_stmt->part_key_is_updated(part_key_update))) { LOG_WARN("failed to check part key is updated", K(ret)); } else if (part_key_update && !is_one_part_table) { is_multi_part_dml = true; + OPT_TRACE("insert partition table with update part key, force use multi part dml"); } else if (insert_stmt->has_part_key_sequence() && share::schema::PARTITION_LEVEL_ZERO != table_schema->get_part_level()) { // sequence 作为分区键的值插入分区表或者是insert...update更新了分区键,都需要使用multi table dml is_multi_part_dml = true; + OPT_TRACE("insert partition table with sequence, force use multi part dml"); } else if (OB_FAIL(insert_stmt->part_key_has_rand_value(has_rand_part_key))) { LOG_WARN("check part key has rand value failed", K(ret)); } else if (OB_FAIL(insert_stmt->part_key_has_subquery(has_subquery_part_key))) { @@ -711,6 +809,11 @@ int ObInsertLogPlan::check_insert_stmt_need_multi_partition_dml(bool &is_multi_p LOG_WARN("check to check whether part key contains auto inc column", K(ret)); } else if (has_rand_part_key || has_subquery_part_key || has_auto_inc_part_key) { is_multi_part_dml = true; + OPT_TRACE("part key with rand/subquery/auto_inc expr, force use multi part dml"); + } else if (!insert_table_sharding->is_single() && + (insert_stmt->is_insert_up() || insert_stmt->is_replace())) { + is_multi_part_dml = true; + OPT_TRACE("insert up/replace force use multi part dml"); } else { /*do nothing*/ } if (OB_SUCC(ret)) { LOG_TRACE("succeed to check insert_stmt need multi-partition-dml", K(is_multi_part_dml)); @@ -718,50 +821,6 @@ int ObInsertLogPlan::check_insert_stmt_need_multi_partition_dml(bool &is_multi_p return ret; } -int ObInsertLogPlan::check_insert_location_need_multi_partition_dml(ObLogicalOperator &top, - ObTablePartitionInfo *insert_table_part, - ObShardingInfo *insert_sharding, - bool is_one_part_table, - bool &is_multi_part_dml) -{ - int ret = OB_SUCCESS; - bool is_basic = false; - bool is_partition_wise = false; - const ObInsertStmt *insert_stmt = NULL; - is_multi_part_dml = false; - if (OB_ISNULL(insert_table_part) || OB_ISNULL(insert_sharding) || - OB_ISNULL(insert_stmt = get_stmt())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(insert_table_part), K(insert_sharding), - K(insert_stmt), K(ret)); - } else if (0 == insert_table_part->get_phy_tbl_location_info().get_partition_cnt()) { - is_multi_part_dml = true; - } else if (OB_FAIL(check_basic_sharding_for_insert_stmt(*insert_sharding, - top, - is_basic))) { - LOG_WARN("failed to compute basic sharding info", K(ret)); - } else if (insert_sharding->is_local() || is_basic) { - if (is_one_part_table || !insert_table_part->get_table_location().is_part_or_subpart_all_partition()) { - is_multi_part_dml = false; - } else { - is_multi_part_dml = true; - } - } else if (OB_FAIL(check_if_match_partition_wise_insert(*insert_sharding, - top, - is_partition_wise))) { - LOG_WARN("failed to check if match partition wise insert", K(ret)); - } else if (is_partition_wise) { - is_multi_part_dml = false; - } else { - is_multi_part_dml = true; - } - if (OB_SUCC(ret)) { - LOG_TRACE("succeed to check insert location need multi_partition_dml", K(is_multi_part_dml), - K(is_partition_wise)); - } - return ret; -} - int ObInsertLogPlan::check_basic_sharding_for_insert_stmt(ObShardingInfo &target_sharding, ObLogicalOperator &child, bool &is_basic) diff --git a/src/sql/optimizer/ob_insert_log_plan.h b/src/sql/optimizer/ob_insert_log_plan.h index 6b7c8c846c..93842599b8 100644 --- a/src/sql/optimizer/ob_insert_log_plan.h +++ b/src/sql/optimizer/ob_insert_log_plan.h @@ -56,7 +56,7 @@ protected: int build_lock_row_flag_expr(ObConstRawExpr *&lock_row_flag_expr); int create_insert_plans(ObIArray &candi_plans, ObTablePartitionInfo *insert_table_part, - ObShardingInfo *insert_sharding, + ObShardingInfo *insert_table_sharding, ObConstRawExpr *lock_row_flag_expr, const bool force_no_multi_part, const bool force_multi_part, @@ -65,22 +65,21 @@ protected: int allocate_insert_as_top(ObLogicalOperator *&top, ObRawExpr *lock_row_flag_expr, ObTablePartitionInfo *table_partition_info, - ObShardingInfo *insert_sharding, + ObShardingInfo *insert_op_sharding, bool is_multi_part); int candi_allocate_pdml_insert(OSGShareInfo *osg_info); int candi_allocate_optimizer_stats_merge(OSGShareInfo *osg_info); - virtual int check_insert_need_multi_partition_dml(ObLogicalOperator &top, - ObTablePartitionInfo *insert_table_partition, - ObShardingInfo *insert_sharding, - bool &is_multi_part_dml); - virtual int check_insert_stmt_need_multi_partition_dml(bool &is_multi_part_dml, - bool &is_one_part_table); - virtual int check_insert_location_need_multi_partition_dml(ObLogicalOperator &top, - ObTablePartitionInfo *insert_table_partition, - ObShardingInfo *insert_sharding, - bool is_one_part_table, - bool &is_multi_part_dml); + virtual int get_best_insert_dist_method(ObLogicalOperator &top, + ObTablePartitionInfo *insert_table_partition, + ObShardingInfo *insert_table_sharding, + const bool force_no_multi_part, + const bool force_multi_part, + int64_t &distributed_methods, + bool &is_multi_part_dml); + virtual int check_insert_plan_need_multi_partition_dml(ObTablePartitionInfo *insert_table_partition, + ObShardingInfo *insert_table_sharding, + bool &is_multi_part_dml); int check_basic_sharding_for_insert_stmt(ObShardingInfo &target_sharding, ObLogicalOperator &child, bool &is_basic);