/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/ob_physical_plan.h" #include "share/ob_define.h" #include "lib/utility/utility.h" #include "lib/utility/serialization.h" #include "lib/alloc/malloc_hook.h" #include "share/inner_table/ob_inner_table_schema.h" #include "share/schema/ob_schema_getter_guard.h" #include "common/sql_mode/ob_sql_mode_utils.h" #include "sql/ob_result_set.h" #include "sql/ob_sql_utils.h" #include "sql/session/ob_sql_session_info.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_sql_expression.h" #include "sql/engine/ob_phy_operator_type.h" #include "observer/mysql/ob_mysql_request_manager.h" #include "share/diagnosis/ob_sql_plan_monitor_node_list.h" #include "sql/engine/ob_operator.h" #include "sql/engine/ob_operator_factory.h" #include "share/stat/ob_opt_stat_manager.h" #include "share/ob_truncated_string.h" namespace oceanbase { using namespace common; using namespace common::serialization; using namespace share::schema; using namespace lib; namespace sql { ObPhysicalPlan::ObPhysicalPlan(MemoryContext &mem_context /* = CURRENT_CONTEXT */) : ObPlanCacheObject(ObLibCacheNameSpace::NS_CRSR, mem_context), phy_hint_(), root_op_spec_(NULL), param_count_(0), signature_(0), field_columns_(mem_context->get_arena_allocator()), param_columns_(mem_context->get_arena_allocator()), returning_param_columns_(mem_context->get_arena_allocator()), autoinc_params_(allocator_), stmt_need_privs_(allocator_), stmt_ora_need_privs_(allocator_), audit_units_(allocator_), vars_(allocator_), sql_expression_factory_(allocator_), expr_op_factory_(allocator_), literal_stmt_type_(stmt::T_NONE), plan_type_(OB_PHY_PLAN_UNINITIALIZED), location_type_(OB_PHY_PLAN_UNINITIALIZED), require_local_execution_(false), use_px_(false), px_dop_(0), next_phy_operator_id_(0), next_expr_operator_id_(0), regexp_op_count_(0), like_op_count_(0), px_exchange_out_op_count_(0), is_sfu_(false), is_contains_assignment_(false), affected_last_insert_id_(false), is_affect_found_row_(false), has_top_limit_(false), is_wise_join_(false), contain_table_scan_(false), has_nested_sql_(false), session_id_(0), contain_oracle_trx_level_temporary_table_(false), contain_oracle_session_level_temporary_table_(false), concurrent_num_(0), max_concurrent_num_(ObMaxConcurrentParam::UNLIMITED), table_locations_(allocator_), das_table_locations_(allocator_), row_param_map_(allocator_), is_update_uniq_index_(false), contain_index_location_(false), base_constraints_(allocator_), strict_constrinats_(allocator_), non_strict_constrinats_(allocator_), expr_frame_info_(allocator_), stat_(), op_stats_(), need_drive_dml_query_(false), is_returning_(false), is_late_materialized_(false), is_dep_base_table_(false), is_insert_select_(false), is_plain_insert_(false), flashback_query_items_(allocator_), contain_paramed_column_field_(false), first_array_index_(OB_INVALID_INDEX), need_consistent_snapshot_(true), is_batched_multi_stmt_(false), encrypt_meta_array_(allocator_), is_new_engine_(false), use_pdml_(false), use_temp_table_(false), has_link_table_(false), need_serial_exec_(false), temp_sql_can_prepare_(false), is_need_trans_(false), batch_size_(0), contain_pl_udf_or_trigger_(false), ddl_schema_version_(0), ddl_table_id_(0), ddl_execution_id_(0), ddl_task_id_(0), is_packed_(false), has_instead_of_trigger_(false) { } ObPhysicalPlan::~ObPhysicalPlan() { destroy(); } void ObPhysicalPlan::reset() { ObPlanCacheObject::reset(); phy_hint_.reset(); root_op_spec_ = NULL; param_count_ = 0; signature_ = 0; field_columns_.reset(); param_columns_.reset(); returning_param_columns_.reset(); autoinc_params_.reset(); stmt_need_privs_.reset(); stmt_ora_need_privs_.reset(); audit_units_.reset(); vars_.reset(); sql_expression_factory_.destroy(); expr_op_factory_.destroy(); literal_stmt_type_ = stmt::T_NONE; plan_type_ = OB_PHY_PLAN_UNINITIALIZED; location_type_ = OB_PHY_PLAN_UNINITIALIZED; require_local_execution_ = false; use_px_ = false; px_dop_ = 0; next_phy_operator_id_ = 0; next_expr_operator_id_ = 0; regexp_op_count_ = 0; like_op_count_ = 0; px_exchange_out_op_count_ = 0; is_sfu_ = false; is_contain_virtual_table_ = false; is_contain_inner_table_ = false; is_contains_assignment_ = false; affected_last_insert_id_ = false; is_affect_found_row_ = false; has_top_limit_ = false; is_wise_join_ = false; contain_table_scan_ = false; has_nested_sql_ = false; session_id_ = 0; contain_oracle_trx_level_temporary_table_ = false; contain_oracle_session_level_temporary_table_ = false; concurrent_num_ = 0; max_concurrent_num_ = ObMaxConcurrentParam::UNLIMITED; is_update_uniq_index_ = false; contain_index_location_ = false; ObPlanCacheObject::reset(); is_returning_ = false; is_late_materialized_ = false; is_dep_base_table_ = false; is_insert_select_ = false; is_plain_insert_ = false; base_constraints_.reset(); strict_constrinats_.reset(); non_strict_constrinats_.reset(); flashback_query_items_.reset(); contain_paramed_column_field_ = false; first_array_index_ = OB_INVALID_INDEX; need_consistent_snapshot_ = true; is_batched_multi_stmt_ = false; temp_sql_can_prepare_ = false; is_new_engine_ = false; #ifndef NDEBUG bit_set_.reset(); #endif use_pdml_ = false; use_temp_table_ = false; has_link_table_ = false; encrypt_meta_array_.reset(); need_serial_exec_ = false; batch_size_ = 0; contain_pl_udf_or_trigger_ = false; is_packed_ = false; has_instead_of_trigger_ = false; stat_.expected_worker_map_.destroy(); stat_.minimal_worker_map_.destroy(); } void ObPhysicalPlan::destroy() { #ifndef NDEBUG bit_set_.reset(); #endif sql_expression_factory_.destroy(); expr_op_factory_.destroy(); stat_.expected_worker_map_.destroy(); stat_.minimal_worker_map_.destroy(); } int ObPhysicalPlan::copy_common_info(ObPhysicalPlan &src) { int ret = OB_SUCCESS; //copy regexp_op_count_ set_regexp_op_count(src.regexp_op_count_); set_like_op_count(src.like_op_count_); set_px_exchange_out_op_count(src.px_exchange_out_op_count_); //copy others set_fetch_cur_time(src.get_fetch_cur_time()); set_stmt_type(src.get_stmt_type()); set_literal_stmt_type(src.get_literal_stmt_type()); //copy plan_id/hint/privs object_id_ = src.object_id_; if (OB_FAIL(set_phy_plan_hint(src.get_phy_plan_hint()))) { LOG_WARN("Failed to copy query hint", K(ret)); } else if (OB_FAIL(set_stmt_need_privs(src.get_stmt_need_privs()))) { LOG_WARN("Failed to deep copy", K(src.get_stmt_need_privs()), K(ret)); } else { }//do nothing return ret; } int ObPhysicalPlan::set_vars(const common::ObIArray &vars) { int ret = OB_SUCCESS; int64_t N = vars.count(); if (N > 0 && OB_FAIL(vars_.reserve(N))) { OB_LOG(WARN, "fail to reserve vars", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { const ObVarInfo &var_info = vars.at(i); ObVarInfo clone_var_info; if (OB_FAIL(var_info.deep_copy(allocator_, clone_var_info))) { LOG_WARN("fail to deep copy var info", K(ret), K(var_info)); } else if (OB_FAIL(vars_.push_back(clone_var_info))) { // deep_copy时只写了ObString对象,ObString对象可以在allocator_析构的时候完全释放掉,因此这里不用调ObString的析构函数 LOG_WARN("fail to push back vars", K(ret), K(clone_var_info)); } } return ret; } int ObPhysicalPlan::init_params_info_str() { int ret = common::OB_SUCCESS; int64_t N = params_info_.count(); int64_t buf_len = N * ObParamInfo::MAX_STR_DES_LEN + 1; int64_t pos = 0; char *buf = (char *)allocator_.alloc(buf_len); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; SQL_PC_LOG(WARN, "fail to alloc memory for param info", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) { if (N - 1 != i) { if (OB_FAIL(databuff_printf(buf, buf_len, pos, "{%d,%d,%d,%d,%d},", params_info_.at(i).flag_.need_to_check_type_, params_info_.at(i).flag_.need_to_check_bool_value_, params_info_.at(i).flag_.expected_bool_value_, params_info_.at(i).scale_, params_info_.at(i).type_))) { SQL_PC_LOG(WARN, "fail to buff_print param info", K(ret)); } } else { if (OB_FAIL(databuff_printf(buf, buf_len, pos, "{%d,%d,%d,%d,%d}", params_info_.at(i).flag_.need_to_check_type_, params_info_.at(i).flag_.need_to_check_bool_value_, params_info_.at(i).flag_.expected_bool_value_, params_info_.at(i).scale_, params_info_.at(i).type_))) { SQL_PC_LOG(WARN, "fail to buff_print param info", K(ret)); } } } } if (OB_SUCC(ret)) { if (OB_FAIL(ob_write_string(allocator_, ObString(pos, buf), stat_.param_infos_))) { SQL_PC_LOG(WARN, "fail to deep copy param infos", K(ret)); } } return ret; } int ObPhysicalPlan::set_field_columns(const ColumnsFieldArray &fields) { int ret = OB_SUCCESS; ObField field; WITH_CONTEXT(mem_context_) { int64_t N = fields.count(); if (N > 0 && OB_FAIL(field_columns_.reserve(N))) { OB_LOG(WARN, "fail to reserve field column", K(ret)); } for (int i = 0; OB_SUCC(ret) && i < N; ++i) { const ObField &ofield = fields.at(i); LOG_DEBUG("ofield info", K(ofield)); if (!contain_paramed_column_field_ && ofield.is_paramed_select_item_) { if (OB_ISNULL(ofield.paramed_ctx_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid paramed ctx", K(ofield.paramed_ctx_), K(i)); } else if (ofield.paramed_ctx_->param_idxs_.count() > 0) { contain_paramed_column_field_ = true; } } if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(field.deep_copy(ofield, &allocator_))) { LOG_WARN("deep copy field failed", K(ret)); } else if (OB_FAIL(field_columns_.push_back(field))) { LOG_WARN("push back field columns failed", K(ret)); } else { LOG_DEBUG("succ to push back field columns", K(field)); } } } return ret; } int ObPhysicalPlan::set_param_fields(const common::ParamsFieldArray ¶ms) { int ret = OB_SUCCESS; int64_t N = params.count(); WITH_CONTEXT(mem_context_) { if(N > 0 && OB_FAIL(param_columns_.reserve(N))) { LOG_WARN("failed to reserved param field", K(ret)); } ObField tmp_field; for (int i = 0; OB_SUCC(ret) && i < N; ++i) { const ObField ¶m_field = params.at(i); if (OB_FAIL(tmp_field.deep_copy(param_field, &allocator_))) { LOG_WARN("deep copy field failed", K(ret)); } else if (OB_FAIL(param_columns_.push_back(tmp_field))) { LOG_WARN("push back field columns failed", K(ret)); } } } return ret; } int ObPhysicalPlan::set_returning_param_fields(const common::ParamsFieldArray ¶ms) { int ret = OB_SUCCESS; int64_t N = params.count(); WITH_CONTEXT(mem_context_) { if(N > 0 && OB_FAIL(returning_param_columns_.reserve(N))) { LOG_WARN("failed to reserved returning param field", K(ret)); } ObField tmp_field; for (int i = 0; OB_SUCC(ret) && i < N; ++i) { const ObField ¶m_field = params.at(i); if (OB_FAIL(tmp_field.deep_copy(param_field, &allocator_))) { LOG_WARN("deep copy field failed", K(ret)); } else if (OB_FAIL(returning_param_columns_.push_back(tmp_field))) { LOG_WARN("push back field columns failed", K(ret)); } } } return ret; } int ObPhysicalPlan::set_autoinc_params(const ObIArray &autoinc_params) { return autoinc_params_.assign(autoinc_params); } int ObPhysicalPlan::set_stmt_need_privs(const ObStmtNeedPrivs& stmt_need_privs) { int ret = OB_SUCCESS; stmt_need_privs_.reset(); if (OB_FAIL(stmt_need_privs_.deep_copy(stmt_need_privs, allocator_))) { LOG_WARN("Failed to deep copy ObStmtNeedPrivs", K_(stmt_need_privs)); } return ret; } int ObPhysicalPlan::set_stmt_ora_need_privs(const ObStmtOraNeedPrivs& stmt_ora_need_privs) { int ret = OB_SUCCESS; stmt_ora_need_privs_.reset(); if (OB_FAIL(stmt_ora_need_privs_.deep_copy(stmt_ora_need_privs, allocator_))) { LOG_WARN("Failed to deep copy ObStmtNeedPrivs", K_(stmt_ora_need_privs)); } return ret; } int ObPhysicalPlan::set_audit_units(const common::ObIArray& audit_units) { return audit_units_.assign(audit_units); } void ObPhysicalPlan::inc_large_querys() { ATOMIC_INC(&(stat_.large_querys_)); } void ObPhysicalPlan::inc_delayed_large_querys() { ATOMIC_INC(&(stat_.delayed_large_querys_)); } void ObPhysicalPlan::inc_delayed_px_querys() { ATOMIC_INC(&(stat_.delayed_px_querys_)); } bool ObPhysicalPlan::is_stmt_modify_trans() const { return is_sfu_ || ObStmt::is_dml_write_stmt(stmt_type_); } int ObPhysicalPlan::init_operator_stats() { int ret = OB_SUCCESS; if (OB_FAIL(op_stats_.init(&allocator_, next_phy_operator_id_))) { LOG_WARN("fail to init op_stats", K(ret)); } return ret; } void ObPhysicalPlan::update_plan_stat(const ObAuditRecordData &record, const bool is_first, const bool is_evolution, const ObIArray *table_row_count_list) { const int64_t current_time = ObTimeUtility::current_time(); int64_t execute_count = 0; if (record.is_timeout()) { ATOMIC_INC(&(stat_.timeout_count_)); ATOMIC_AAF(&(stat_.total_process_time_), record.get_process_time()); } else if (!GCONF.enable_perf_event) { // short route ATOMIC_AAF(&(stat_.elapsed_time_), record.get_elapsed_time()); ATOMIC_AAF(&(stat_.cpu_time_), record.get_elapsed_time() - record.exec_record_.wait_time_end_ - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); if (is_first) { ATOMIC_STORE(&(stat_.hit_count_), 0); } else { ATOMIC_INC(&(stat_.hit_count_)); } } else { // long route stat begin execute_count = ATOMIC_AAF(&stat_.execute_times_, 1); ATOMIC_AAF(&(stat_.total_process_time_), record.get_process_time()); ATOMIC_AAF(&(stat_.disk_reads_), record.exec_record_.get_io_read_count()); ATOMIC_AAF(&(stat_.direct_writes_), record.exec_record_.get_io_write_count()); ATOMIC_AAF(&(stat_.buffer_gets_), 2 * record.exec_record_.get_row_cache_hit() + 2 * record.exec_record_.get_fuse_row_cache_hit() + 2 * record.exec_record_.get_bloom_filter_filts() + record.exec_record_.get_block_cache_hit() + record.exec_record_.get_io_read_count()); ATOMIC_AAF(&(stat_.application_wait_time_), record.exec_record_.get_application_time()); ATOMIC_AAF(&(stat_.concurrency_wait_time_), record.exec_record_.get_concurrency_time()); ATOMIC_AAF(&(stat_.user_io_wait_time_), record.exec_record_.get_user_io_time()); ATOMIC_AAF(&(stat_.rows_processed_), record.return_rows_ + record.affected_rows_); ATOMIC_AAF(&(stat_.elapsed_time_), record.get_elapsed_time()); ATOMIC_AAF(&(stat_.cpu_time_), record.get_elapsed_time() - record.exec_record_.wait_time_end_ - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); // ATOMIC_STORE(&(stat_.expected_worker_count_), record.expected_worker_cnt_); if (is_first) { ATOMIC_STORE(&(stat_.hit_count_), 0); } else { ATOMIC_INC(&(stat_.hit_count_)); } if (record.get_elapsed_time() > GCONF.trace_log_slow_query_watermark) { ATOMIC_INC(&(stat_.slow_count_)); } int64_t slowest_usec = ATOMIC_LOAD(&stat_.slowest_exec_usec_); if (slowest_usec < record.get_elapsed_time()) { ATOMIC_STORE(&(stat_.slowest_exec_usec_), record.get_elapsed_time()); ATOMIC_STORE(&(stat_.slowest_exec_time_), current_time); } if (stat_.table_row_count_first_exec_ != NULL && table_row_count_list != NULL) { int64_t access_table_num = stat_.access_table_num_; int64_t max_index = std::min(access_table_num, std::min(table_row_count_list->count(), OB_MAX_TABLE_NUM_PER_STMT)); if (is_first) { for (int64_t i = 0; i < max_index; ++i) { ATOMIC_STORE(&(stat_.table_row_count_first_exec_[i].op_id_), table_row_count_list->at(i).op_id_); ATOMIC_STORE(&(stat_.table_row_count_first_exec_[i].row_count_), table_row_count_list->at(i).row_count_); LOG_DEBUG("first add row stat", K(table_row_count_list->at(i))); } // for end } else if (record.get_elapsed_time() > SLOW_QUERY_TIME_FOR_PLAN_EXPIRE) { for (int64_t i = 0; !is_expired() && i < max_index; ++i) { for (int64_t j = 0; !is_expired() && j < max_index; ++j) { // 一些场景比如并行执行时,不同次执行表的行信息存储的顺序可能不同 if (table_row_count_list->at(i).op_id_ == stat_.table_row_count_first_exec_[j].op_id_) { int64_t first_exec_row_count = ATOMIC_LOAD(&stat_.table_row_count_first_exec_[j] .row_count_); if (first_exec_row_count == -1) { // do nothing } else if (check_if_is_expired(first_exec_row_count, table_row_count_list->at(i).row_count_)) { set_is_expired(true); LOG_INFO("plan is expired", K(first_exec_row_count), K(table_row_count_list->at(i)), "current_elapsed_time", record.get_elapsed_time(), "plan_stat", stat_); } } } // for max_index end } // for max_index end } } ATOMIC_STORE(&(stat_.last_active_time_), current_time); if (ATOMIC_LOAD(&stat_.is_evolution_)) { //for spm ATOMIC_INC(&(stat_.evolution_stat_.executions_)); ATOMIC_AAF(&(stat_.evolution_stat_.cpu_time_), record.get_elapsed_time() - record.exec_record_.wait_time_end_ - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); ATOMIC_AAF(&(stat_.evolution_stat_.elapsed_time_), record.get_elapsed_time()); } if (stat_.is_bind_sensitive_ && execute_count > 0) { int64_t pos = execute_count % ObPlanStat::MAX_SCAN_STAT_SIZE; ATOMIC_STORE(&(stat_.table_scan_stat_[pos].query_range_row_count_), record.table_scan_stat_.query_range_row_count_); ATOMIC_STORE(&(stat_.table_scan_stat_[pos].indexback_row_count_), record.table_scan_stat_.indexback_row_count_); ATOMIC_STORE(&(stat_.table_scan_stat_[pos].output_row_count_), record.table_scan_stat_.output_row_count_); } } // long route stat ends if (!is_expired() && stat_.enable_plan_expiration_) { if (record.is_timeout() || record.status_ == OB_SESSION_KILLED) { set_is_expired(true); LOG_INFO("query plan is expired due to execution timeout", K(stat_)); } else if (is_first) { ATOMIC_STORE(&(stat_.sample_times_), 0); ATOMIC_STORE(&(stat_.first_exec_row_count_), record.exec_record_.get_memstore_read_row_count() + record.exec_record_.get_ssstore_read_row_count()); ATOMIC_STORE(&(stat_.first_exec_usec_), record.get_elapsed_time() - record.exec_record_.wait_time_end_ - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); } else if (0 == stat_.sample_times_) { // first sample query ATOMIC_INC(&(stat_.sample_times_)); ATOMIC_STORE(&(stat_.sample_exec_row_count_), record.exec_record_.get_memstore_read_row_count() + record.exec_record_.get_ssstore_read_row_count()); ATOMIC_STORE(&(stat_.sample_exec_usec_), record.get_elapsed_time() - record.exec_record_.wait_time_end_ - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); } else { int64_t sample_count = ATOMIC_AAF(&(stat_.sample_times_), 1); int64_t sample_exec_row_count = ATOMIC_AAF(&(stat_.sample_exec_row_count_), record.exec_record_.get_memstore_read_row_count() + record.exec_record_.get_ssstore_read_row_count()); int64_t sample_exec_usec = ATOMIC_AAF(&(stat_.sample_exec_usec_), record.get_elapsed_time() - record.exec_record_.wait_time_end_ - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); if (sample_count < SLOW_QUERY_SAMPLE_SIZE) { // do nothing when query execution samples are not enough } else { if (stat_.cpu_time_ <= SLOW_QUERY_TIME_FOR_PLAN_EXPIRE * stat_.execute_times_) { // do nothing for fast query } else if (is_plan_unstable(sample_count, sample_exec_row_count, sample_exec_usec)) { set_is_expired(true); } ATOMIC_STORE(&(stat_.sample_times_), 0); } } } } bool ObPhysicalPlan::is_plan_unstable(const int64_t sample_count, const int64_t sample_exec_row_count, const int64_t sample_exec_usec) { bool bret = false; if (sample_exec_usec <= SLOW_QUERY_TIME_FOR_PLAN_EXPIRE * sample_count) { // sample query is fast query in the average } else if (OB_PHY_PLAN_LOCAL == plan_type_) { int64_t first_query_range_rows = ATOMIC_LOAD(&stat_.first_exec_row_count_); if (sample_exec_row_count <= SLOW_QUERY_ROW_COUNT_THRESOLD * sample_count) { // the sample query does not accesses too many rows in the average } else if (sample_exec_row_count / sample_count > first_query_range_rows * 10) { // the average sample query range row count increases great bret = true; LOG_INFO("local query plan is expired due to unstable performance", K(bret), K(stat_.execute_times_), K(first_query_range_rows), K(sample_exec_row_count), K(sample_count)); } } else if ( OB_PHY_PLAN_DISTRIBUTED == plan_type_) { int64_t first_exec_usec = ATOMIC_LOAD(&stat_.first_exec_usec_); if (sample_exec_usec / sample_count > first_exec_usec * 2) { // the average sample query execute time increases great bret = true; LOG_INFO("distribute query plan is expired due to unstable performance", K(bret), K(stat_.execute_times_), K(first_exec_usec), K(sample_exec_usec), K(sample_count)); } } else { // do nothing } return bret; } int64_t ObPhysicalPlan::get_evo_perf() const { int64_t v = 0; if (0 == stat_.evolution_stat_.executions_) { v = 0; } else { v = stat_.evolution_stat_.cpu_time_/ stat_.evolution_stat_.executions_; } return v; } /** * 目前采3个指标来淘汰计划,只有同时满足这3个条件,才会触发计划的淘汰: * 1. 当前行数超过阈值(100行) * 2. 执行时间超过阈值(5ms) * 3. 表扫描行数与原扫描行数比值超过阈值(2倍) * * 设置当前行数阈值的原因是因为表扫描函数并不能保证递增,在频繁插入删除的情况下,原来的表扫描函数 * 可能会保持在一个较低的值,这时候计划淘汰会很频繁, * 设置一个阈值的可以在很大程度上缓解计划淘汰的频率 */ inline bool ObPhysicalPlan::check_if_is_expired(const int64_t first_exec_row_count, const int64_t current_row_count) const { bool ret_bool = false; if (current_row_count <= EXPIRED_PLAN_TABLE_ROW_THRESHOLD) { // 100 行 ret_bool = false; } else { ret_bool = ((first_exec_row_count == 0 && current_row_count > 0) || (first_exec_row_count > 0 && current_row_count / first_exec_row_count > TABLE_ROW_CHANGE_THRESHOLD)); } return ret_bool; } int ObPhysicalPlan::inc_concurrent_num() { int ret = OB_SUCCESS; int64_t concurrent_num = 0; int64_t new_num = 0; bool is_succ = false; if (max_concurrent_num_ == ObMaxConcurrentParam::UNLIMITED) { ret = OB_ERR_UNEXPECTED; LOG_WARN("current physical plan is unlimit", K(ret), K(max_concurrent_num_)); } else { while(OB_SUCC(ret) && false == is_succ) { concurrent_num = ATOMIC_LOAD(&concurrent_num_); if (concurrent_num >= max_concurrent_num_) { ret = OB_REACH_MAX_CONCURRENT_NUM; } else { new_num = concurrent_num + 1; is_succ = ATOMIC_BCAS(&concurrent_num_, concurrent_num, new_num); } } } return ret; } void ObPhysicalPlan::dec_concurrent_num() { ATOMIC_DEC(&concurrent_num_); } int ObPhysicalPlan::set_max_concurrent_num(int64_t max_concurrent_num) { int ret = OB_SUCCESS; if (max_concurrent_num < 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid max_concurrent_num", K(ret), K(max_concurrent_num)); } else { ATOMIC_STORE(&max_concurrent_num_, max_concurrent_num); } return ret; } int64_t ObPhysicalPlan::get_max_concurrent_num() { return ATOMIC_LOAD(&max_concurrent_num_); } OB_SERIALIZE_MEMBER(FlashBackQueryItem, table_id_, time_val_); //因为还没看到远程执行对force_trace_log的处理,所以暂时不序列化 OB_SERIALIZE_MEMBER(ObPhysicalPlan, tenant_schema_version_, //该字段执行期没被使用 phy_hint_.query_timeout_, phy_hint_.read_consistency_, is_sfu_, dependency_tables_, param_count_, plan_type_, signature_, stmt_type_, regexp_op_count_, literal_stmt_type_, like_op_count_, is_ignore_stmt_, object_id_, stat_.sql_id_, is_contain_inner_table_, is_update_uniq_index_, dummy_string_, is_returning_, location_type_, use_px_, vars_, px_dop_, has_nested_sql_, flashback_query_items_, stat_.enable_early_lock_release_, encrypt_meta_array_, use_pdml_, is_new_engine_, use_temp_table_, batch_size_, need_drive_dml_query_, is_need_trans_, contain_oracle_trx_level_temporary_table_, ddl_schema_version_, ddl_table_id_, phy_hint_.monitor_, need_serial_exec_, contain_pl_udf_or_trigger_, is_packed_, has_instead_of_trigger_, is_plain_insert_, ddl_execution_id_, ddl_task_id_, stat_.plan_id_); int ObPhysicalPlan::set_table_locations(const ObTablePartitionInfoArray &infos, ObSchemaGetterGuard &schema_guard) { int ret = OB_SUCCESS; table_locations_.reset(); das_table_locations_.reset(); if (OB_FAIL(table_locations_.init(infos.count()))) { LOG_WARN("fail to init table location count", K(ret)); } else if (OB_FAIL(das_table_locations_.init(infos.count()))) { LOG_WARN("fail to init das table location count", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < infos.count(); ++i) { ObTableLocation &tl = infos.at(i)->get_table_location(); const ObTableSchema *table_schema = nullptr; if (tl.use_das()) { if (OB_FAIL(das_table_locations_.push_back(tl))) { LOG_WARN("fail to push das table location", K(ret), K(i)); } } else if (OB_FAIL(table_locations_.push_back(tl))) { LOG_WARN("fail to push table location", K(ret), K(i)); } else if (OB_FAIL(schema_guard.get_table_schema(MTL_ID(), tl.get_ref_table_id(), table_schema))) { LOG_WARN("get table schema failed", K(ret), K(tl.get_ref_table_id())); } else { contain_index_location_ |= table_schema->is_index_table(); } LOG_DEBUG("set table location", K(tl), K(tl.use_das())); } return ret; } int ObPhysicalPlan::set_location_constraints(const ObIArray &base_constraints, const ObIArray &strict_constraints, const ObIArray &non_strict_constraints) { // deep copy location constraints int ret = OB_SUCCESS; if (base_constraints.count() > 0) { base_constraints_.reset(); base_constraints_.set_allocator(&allocator_); if (OB_FAIL(base_constraints_.init(base_constraints.count()))) { LOG_WARN("failed to init base constraints", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < base_constraints.count(); ++i) { if (OB_FAIL(base_constraints_.push_back(base_constraints.at(i)))) { LOG_WARN("failed to push back element", K(ret), K(base_constraints.at(i))); } else { /*do nothing*/ } } } if (OB_SUCC(ret) && strict_constraints.count() > 0) { strict_constrinats_.reset(); strict_constrinats_.set_allocator(&allocator_); if (OB_FAIL(strict_constrinats_.init(strict_constraints.count()))) { LOG_WARN("failed to init strict constraints", K(ret)); } else if (OB_FAIL(strict_constrinats_.prepare_allocate(strict_constraints.count()))) { LOG_WARN("failed to prepare allocate location constraints", K(ret)); } else { ObPwjConstraint *cur_cons; for (int64_t i = 0; OB_SUCC(ret) && i < strict_constraints.count(); ++i) { if (OB_ISNULL(cur_cons = strict_constraints.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(i)); } else if (cur_cons->count() <= 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected empty array", K(ret)); } else { strict_constrinats_.at(i).reset(); strict_constrinats_.at(i).set_allocator(&allocator_); if (OB_FAIL(strict_constrinats_.at(i).init(cur_cons->count()))) { LOG_WARN("failed to init fixed array", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < cur_cons->count(); ++j) { if (OB_FAIL(strict_constrinats_.at(i).push_back(cur_cons->at(j)))) { LOG_WARN("failed to push back element", K(ret), K(cur_cons->at(j))); } else { /*do nothing*/ } } } } } } if (OB_SUCC(ret) && non_strict_constraints.count() > 0) { non_strict_constrinats_.reset(); non_strict_constrinats_.set_allocator(&allocator_); if (OB_FAIL(non_strict_constrinats_.init(non_strict_constraints.count()))) { LOG_WARN("failed to init strict constraints", K(ret)); } else if (OB_FAIL(non_strict_constrinats_.prepare_allocate(non_strict_constraints.count()))) { LOG_WARN("failed to prepare allocate location constraints", K(ret)); } else { ObPwjConstraint *cur_cons; for (int64_t i = 0; OB_SUCC(ret) && i < non_strict_constraints.count(); ++i) { if (OB_ISNULL(cur_cons = non_strict_constraints.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(i)); } else if (cur_cons->count() <= 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected empty array", K(ret)); } else { non_strict_constrinats_.at(i).reset(); non_strict_constrinats_.at(i).set_allocator(&allocator_); if (OB_FAIL(non_strict_constrinats_.at(i).init(cur_cons->count()))) { LOG_WARN("failed to init fixed array", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < cur_cons->count(); ++j) { if (OB_FAIL(non_strict_constrinats_.at(i).push_back(cur_cons->at(j)))) { LOG_WARN("failed to push back element", K(ret), K(cur_cons->at(j))); } else { /*do nothing*/ } } } } } } if (OB_FAIL(ret)) { base_constraints_.reset(); strict_constrinats_.reset(); non_strict_constrinats_.reset(); } else { LOG_DEBUG("deep copied location constraints", K(base_constraints_), K(strict_constrinats_), K(non_strict_constrinats_)); } return ret; } DEF_TO_STRING(FlashBackQueryItem) { int64_t pos = 0; J_OBJ_START(); J_KV(K_(table_id)); J_KV(K_(time_val)); J_OBJ_END(); return pos; } int ObPhysicalPlan::alloc_op_spec(const ObPhyOperatorType type, const int64_t child_cnt, ObOpSpec *&op, const uint64_t op_id) { int ret = OB_SUCCESS; UNUSED(op_id); if (type >= PHY_END || child_cnt < 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(type), K(child_cnt)); } else if (OB_FAIL(ObOperatorFactory::alloc_op_spec( allocator_, type, child_cnt, op))) { LOG_WARN("allocate operator spec failed", K(ret)); } else if (OB_ISNULL(op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL operator spec returned", K(ret)); } else { // 这里是直接将log operator id赋值给 spec uint32_t tmp_op_id = UINT32_MAX; if (OB_INVALID_ID != op_id) { tmp_op_id = op_id; } else { tmp_op_id = next_phy_operator_id_++; } op->id_ = tmp_op_id; op->plan_ = this; op->max_batch_size_ = (ObOperatorFactory::is_vectorized(type)) ? batch_size_ : 0; } return ret; } int ObPhysicalPlan::get_encrypt_meta(const uint64_t table_id, ObIArray &metas, const ObIArray *&ret_ptr) const { int ret = OB_SUCCESS; metas.reset(); ARRAY_FOREACH_N(encrypt_meta_array_, i, cnt) { if (encrypt_meta_array_.at(i).table_id_ == table_id) { ret = metas.push_back(encrypt_meta_array_.at(i)); } } if (OB_FAIL(ret)) { LOG_WARN("get table encrypt meta fail", KR(ret), K(table_id)); } else { ret_ptr = &metas; } return ret; } int64_t ObPhysicalPlan::get_pre_expr_ref_count() const { int64_t ret = 0; if (OB_ISNULL(stat_.pre_cal_expr_handler_)) { } else { ret = stat_.pre_cal_expr_handler_->get_ref_count(); } return ret; } void ObPhysicalPlan::inc_pre_expr_ref_count() { if (OB_ISNULL(stat_.pre_cal_expr_handler_)) { LOG_WARN("pre-calcuable expression handler has not been initalized."); } else { stat_.pre_cal_expr_handler_->inc_ref_cnt(); } } void ObPhysicalPlan::dec_pre_expr_ref_count() { if (OB_ISNULL(stat_.pre_cal_expr_handler_)) { } else { PreCalcExprHandler* handler = stat_.pre_cal_expr_handler_; int64_t ref_cnt = handler->dec_ref_cnt(); if (ref_cnt == 0) { common::ObIAllocator* alloc = stat_.pre_cal_expr_handler_->pc_alloc_; stat_.pre_cal_expr_handler_->~PreCalcExprHandler(); alloc->free(stat_.pre_cal_expr_handler_); stat_.pre_cal_expr_handler_ = NULL; } } } int ObPhysicalPlan::before_cache_evicted() { int ret = OB_SUCCESS; dec_pre_expr_ref_count(); return ret; } void ObPhysicalPlan::set_pre_calc_expr_handler(PreCalcExprHandler* handler) { stat_.pre_cal_expr_handler_ = handler; } PreCalcExprHandler* ObPhysicalPlan::get_pre_calc_expr_handler() { return stat_.pre_cal_expr_handler_; } void ObPhysicalPlan::calc_whether_need_trans() { // 这只是一种实现方式,通过看这个plan是否有table参与来决定是否要走事务接口 bool bool_ret = false; if (OB_UNLIKELY(stmt::T_EXPLAIN == stmt_type_)) { // false } else if (get_dependency_table_size() <= 0) { // false } else { for (int64_t i = 0; i < get_dependency_table_size(); ++i) { if (get_dependency_table().at(i).is_base_table()) { const share::schema::ObSchemaObjVersion &table_version = get_dependency_table().at(i); uint64_t table_id = table_version.get_object_id(); if(table_version.is_existed() && (!common::is_virtual_table(table_id) || share::is_oracle_mapping_real_virtual_table(table_id)) && !common::is_cte_table(table_id)) { bool_ret = true; break; } } } } // mysql允许select udf中有dml,需要保证select 整体原子性 if (!bool_ret && contain_pl_udf_or_trigger() && lib::is_mysql_mode() && stmt::T_EXPLAIN != stmt_type_) { bool_ret = true; } is_need_trans_ = bool_ret; } int ObPhysicalPlan::set_expected_worker_map(const common::hash::ObHashMap &c) { int ret = OB_SUCCESS; if (OB_FAIL(assign_worker_map(stat_.expected_worker_map_, c))) { LOG_WARN("set expected worker map failed", K(ret)); } return ret; } const common::hash::ObHashMap& ObPhysicalPlan:: get_expected_worker_map() const { return stat_.expected_worker_map_; } int ObPhysicalPlan::set_minimal_worker_map(const common::hash::ObHashMap &c) { int ret = OB_SUCCESS; if (OB_FAIL(assign_worker_map(stat_.minimal_worker_map_, c))) { LOG_WARN("set minimal worker map failed", K(ret)); } return ret; } const common::hash::ObHashMap& ObPhysicalPlan::get_minimal_worker_map() const { return stat_.minimal_worker_map_; } int ObPhysicalPlan::assign_worker_map(common::hash::ObHashMap &worker_map, const common::hash::ObHashMap &c) { int ret = OB_SUCCESS; if (worker_map.created()) { worker_map.clear(); } else if (OB_FAIL(worker_map.create(common::hash::cal_next_prime(100), ObModIds::OB_SQL_PX, ObModIds::OB_SQL_PX))){ LOG_WARN("create hash map failed", K(ret)); } if (OB_SUCC(ret)) { for (common::hash::ObHashMap::const_iterator it = c.begin(); OB_SUCC(ret) && it != c.end(); ++it) { if (OB_FAIL(worker_map.set_refactored(it->first, it->second))){ SQL_PC_LOG(WARN, "set refactored failed", K(ret), K(it->first), K(it->second)); } } } return ret; } int ObPhysicalPlan::update_cache_obj_stat(ObILibCacheCtx &ctx) { int ret = OB_SUCCESS; ObPlanCacheCtx &pc_ctx = static_cast(ctx); if (OB_ISNULL(pc_ctx.sql_ctx_.session_info_)) { ret = OB_INVALID_ARGUMENT; SQL_PC_LOG(WARN, "session is null", K(ret)); } else { stat_.plan_id_ = get_plan_id(); stat_.plan_hash_value_ = get_signature(); stat_.gen_time_ = ObTimeUtility::current_time(); stat_.schema_version_ = get_tenant_schema_version(); stat_.last_active_time_ = stat_.gen_time_; stat_.hit_count_ = 0; stat_.mem_used_ = get_mem_size(); stat_.slow_count_ = 0; stat_.slowest_exec_time_ = 0; stat_.slowest_exec_usec_ = 0; if (pc_ctx.is_ps_mode_) { ObTruncatedString trunc_stmt(pc_ctx.raw_sql_, OB_MAX_SQL_LENGTH); if (OB_FAIL(ob_write_string(get_allocator(), trunc_stmt.string(), stat_.stmt_))) { SQL_PC_LOG(WARN, "fail to set turncate string", K(ret)); } stat_.ps_stmt_id_ = pc_ctx.fp_result_.pc_key_.key_id_; } else { ObTruncatedString trunc_stmt(pc_ctx.sql_ctx_.spm_ctx_.bl_key_.constructed_sql_, OB_MAX_SQL_LENGTH); if (OB_FAIL(ob_write_string(get_allocator(), trunc_stmt.string(), stat_.stmt_))) { SQL_PC_LOG(WARN, "fail to set turncate string", K(ret)); } } stat_.large_querys_= 0; stat_.delayed_large_querys_= 0; stat_.delayed_px_querys_= 0; stat_.outline_version_ = get_outline_state().outline_version_.version_; stat_.outline_id_ = get_outline_state().outline_version_.object_id_; // Truncate the raw sql to avoid the plan memory being too large due to the long raw sql ObTruncatedString trunc_raw_sql(pc_ctx.raw_sql_, OB_MAX_SQL_LENGTH); if (OB_FAIL(pc_ctx.get_not_param_info_str(get_allocator(), stat_.sp_info_str_))) { SQL_PC_LOG(WARN, "fail to get special param info string", K(ret)); } else if (OB_FAIL(ob_write_string(get_allocator(), pc_ctx.fp_result_.pc_key_.sys_vars_str_, stat_.sys_vars_str_))) { SQL_PC_LOG(DEBUG, "succeed to add plan statistic", "plan_id", get_plan_id(), K(ret)); } else if (OB_FAIL(ob_write_string(get_allocator(), pc_ctx.fp_result_.pc_key_.config_str_, stat_.config_str_))) { SQL_PC_LOG(DEBUG, "failed to add plan statistic", "plan_id", get_plan_id(), K(ret)); } else if (OB_FAIL(init_params_info_str())) { SQL_PC_LOG(DEBUG, "fail to gen param info str", K(ret)); } else if (OB_FAIL(ob_write_string(get_allocator(), trunc_raw_sql.string(), stat_.raw_sql_))) { SQL_PC_LOG(DEBUG, "fail to copy raw sql", "plan_id", get_plan_id(), K(ret)); } else { stat_.sql_cs_type_ = pc_ctx.sql_ctx_.session_info_->get_local_collation_connection(); } if (OB_FAIL(ret)) { // do nothing } else if (get_access_table_num() > 0) { if (OB_ISNULL(stat_.table_row_count_first_exec_ = static_cast( get_allocator().alloc(get_access_table_num() * sizeof(ObTableRowCount))))) { // @banliu.zyd: 这块内存存放计划涉及的表的行数,用于统计信息已经过期的计划的淘汰,分配失败时 // 不报错,走原来不淘汰计划的逻辑 LOG_WARN("allocate memory for table row count list failed", K(get_access_table_num())); } else { for (int64_t i = 0; i < get_access_table_num(); ++i) { stat_.table_row_count_first_exec_[i].op_id_ = OB_INVALID_ID; stat_.table_row_count_first_exec_[i].row_count_ = -1; } } } if (OB_FAIL(ret)) { // do nothing } else if (pc_ctx.tmp_table_names_.count() > 0) { LOG_DEBUG("set tmp table name str", K(pc_ctx.tmp_table_names_)); stat_.sessid_ = pc_ctx.sql_ctx_.session_info_->get_sessid();\ int64_t pos = 0; // fill temporary table name for (int64_t i = 0; OB_SUCC(ret) && i < pc_ctx.tmp_table_names_.count(); i++) { if (OB_ISNULL(stat_.plan_tmp_tbl_name_str_)) { ret = OB_ERR_UNEXPECTED; LOG_DEBUG("null plan tmp tbl id str", K(ret)); } else if (OB_FAIL(databuff_printf(stat_.plan_tmp_tbl_name_str_, ObPlanStat::STMT_MAX_LEN, pos, "%.*s%s", pc_ctx.tmp_table_names_.at(i).length(), pc_ctx.tmp_table_names_.at(i).ptr(), ((i == pc_ctx.tmp_table_names_.count() - 1) ? "" : ", ")))) { if (OB_SIZE_OVERFLOW == ret) { ret = OB_SUCCESS; break; } else { LOG_WARN("failed to write plan tmp tbl name info", K(pc_ctx.tmp_table_names_.at(i)), K(i), K(ret)); } } } if (OB_SUCC(ret)) { stat_.plan_tmp_tbl_name_str_[pos] = '\0'; pos += 1; stat_.plan_tmp_tbl_name_str_len_ = static_cast(pos); } } } return ret; } } //namespace sql } //namespace oceanbase