1351 lines
64 KiB
C++
1351 lines
64 KiB
C++
/**
|
|
* 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_OPT
|
|
#include "lib/utility/ob_tracepoint.h"
|
|
#include "common/ob_smart_call.h"
|
|
#include "sql/optimizer/ob_optimizer.h"
|
|
#include "sql/optimizer/ob_explain_note.h"
|
|
#include "sql/optimizer/ob_log_plan.h"
|
|
#include "sql/optimizer/ob_select_log_plan.h"
|
|
#include "sql/optimizer/ob_log_plan_factory.h"
|
|
#include "sql/optimizer/ob_optimizer_util.h"
|
|
#include "sql/optimizer/ob_logical_operator.h"
|
|
#include "common/ob_smart_call.h"
|
|
#include "sql/ob_optimizer_trace_impl.h"
|
|
#include "sql/engine/cmd/ob_table_direct_insert_service.h"
|
|
#include "sql/dblink/ob_dblink_utils.h"
|
|
#include "sql/resolver/dml/ob_merge_stmt.h"
|
|
#include "sql/optimizer/ob_log_temp_table_insert.h"
|
|
#include "share/stat/ob_opt_system_stat.h"
|
|
#include "sql/optimizer/ob_opt_cost_model_parameter.h"
|
|
#include "src/share/stat/ob_opt_stat_manager.h"
|
|
|
|
using namespace oceanbase;
|
|
using namespace sql;
|
|
using namespace oceanbase::common;
|
|
|
|
int ObOptimizer::optimize(ObDMLStmt &stmt, ObLogPlan *&logical_plan)
|
|
{
|
|
ACTIVE_SESSION_FLAG_SETTER_GUARD(in_sql_optimize);
|
|
int ret = OB_SUCCESS;
|
|
ObLogPlan *plan = NULL;
|
|
const ObQueryCtx *query_ctx = ctx_.get_query_ctx();
|
|
const ObSQLSessionInfo *session = ctx_.get_session_info();
|
|
int64_t last_mem_usage = ctx_.get_allocator().total();
|
|
int64_t optimizer_mem_usage = 0;
|
|
ObDMLStmt *target_stmt = &stmt;
|
|
ObTaskExecutorCtx *task_exec_ctx = ctx_.get_task_exec_ctx();
|
|
if (stmt.is_explain_stmt()) {
|
|
target_stmt = static_cast<ObExplainStmt*>(&stmt)->get_explain_query_stmt();
|
|
}
|
|
if (OB_ISNULL(query_ctx) || OB_ISNULL(session) ||
|
|
OB_ISNULL(target_stmt)|| OB_ISNULL(task_exec_ctx)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arguments", K(ret), K(query_ctx), K(session), K(target_stmt), K(task_exec_ctx));
|
|
} else if (OB_FAIL(init_env_info(*target_stmt))) {
|
|
LOG_WARN("failed to init px info", K(ret));
|
|
} else if (!target_stmt->is_reverse_link() &&
|
|
OB_FAIL(generate_plan_for_temp_table(*target_stmt))) {
|
|
LOG_WARN("failed to generate plan for temp table", K(ret));
|
|
} else if (OB_ISNULL(plan = ctx_.get_log_plan_factory().create(ctx_, stmt))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to create plan", K(ret));
|
|
} else if (OB_FAIL(plan->generate_plan())) {
|
|
LOG_WARN("failed to perform optimization", K(ret));
|
|
} else if (OB_FAIL(plan->add_extra_dependency_table())) {
|
|
LOG_WARN("failed to add extra dependency tables", K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (ctx_.get_exec_ctx()->get_sql_ctx()->is_remote_sql_ &&
|
|
ctx_.get_phy_plan_type() != OB_PHY_PLAN_LOCAL) {
|
|
// set table location to refresh location cache
|
|
ObSEArray<ObTablePartitionInfo*, 8> table_partitions;
|
|
if (OB_FAIL(plan->get_global_table_partition_info(table_partitions))) {
|
|
LOG_WARN("failed to get global table partition info", K(ret));
|
|
} else if (OB_FAIL(task_exec_ctx->set_table_locations(table_partitions))) {
|
|
LOG_WARN("failed to set table locations", K(ret));
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ret = OB_LOCATION_NOT_EXIST;
|
|
LOG_WARN("best plan for remote sql is not local", K(ret), K(ctx_.get_phy_plan_type()));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
logical_plan = plan;
|
|
LOG_TRACE("succ to optimize statement", "stmt", query_ctx->get_sql_stmt(),
|
|
K(logical_plan->get_optimization_cost()));
|
|
}
|
|
optimizer_mem_usage = ctx_.get_allocator().total() - last_mem_usage;
|
|
LOG_TRACE("[SQL MEM USAGE]", K(optimizer_mem_usage), K(last_mem_usage));
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::get_optimization_cost(ObDMLStmt &stmt,
|
|
ObLogPlan *&plan,
|
|
double &cost)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
cost = 0.0;
|
|
ctx_.set_cost_evaluation();
|
|
if (OB_ISNULL(ctx_.get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query ctx is nul", K(ret));
|
|
} else if (OB_ISNULL(plan = ctx_.get_log_plan_factory().create(ctx_, stmt)) ||
|
|
OB_ISNULL(ctx_.get_session_info())) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("failed to create plan", "stmt", ctx_.get_query_ctx()->get_sql_stmt(), K(ret));
|
|
} else if (OB_FAIL(init_env_info(stmt))) {
|
|
LOG_WARN("failed to init env info", K(ret));
|
|
} else if (OB_FAIL(generate_plan_for_temp_table(stmt))) {
|
|
LOG_WARN("failed to generate plan for temp table", K(ret));
|
|
} else if (OB_FAIL(plan->generate_raw_plan())) {
|
|
LOG_WARN("failed to perform optimization", K(ret));
|
|
} else {
|
|
cost = plan->get_optimization_cost();
|
|
OPT_TRACE(plan);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::get_cte_optimization_cost(ObDMLStmt &root_stmt,
|
|
ObSelectStmt *cte_query,
|
|
ObIArray<ObSelectStmt *> &stmts,
|
|
double &cte_cost,
|
|
ObIArray<double> &costs)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
cte_cost = 0.0;
|
|
ctx_.set_cost_evaluation();
|
|
costs.reuse();
|
|
if (OB_ISNULL(ctx_.get_query_ctx()) ||
|
|
OB_ISNULL(ctx_.get_session_info())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query ctx or session info is null", K(ret));
|
|
} else if (OB_FAIL(init_env_info(root_stmt))) {
|
|
LOG_WARN("failed to init env info", K(ret));
|
|
} else if (OB_FAIL(generate_plan_for_temp_table(root_stmt))) {
|
|
LOG_WARN("failed to generate plan for temp table", K(ret));
|
|
}
|
|
if (OB_SUCC(ret) && NULL != cte_query) {
|
|
bool find = false;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !find && i < ctx_.get_temp_table_infos().count(); i ++) {
|
|
ObSqlTempTableInfo *temp_table_info = ctx_.get_temp_table_infos().at(i);
|
|
ObLogPlan *plan = NULL;
|
|
if (OB_ISNULL(temp_table_info) || OB_ISNULL(temp_table_info->table_plan_)
|
|
|| OB_ISNULL(plan = temp_table_info->table_plan_->get_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret));
|
|
} else if (cte_query == temp_table_info->table_query_) {
|
|
find = true;
|
|
if (OB_FAIL(plan->allocate_temp_table_insert_as_top(temp_table_info->table_plan_,
|
|
temp_table_info))) {
|
|
LOG_WARN("failed to allocate temp table insert", K(ret));
|
|
} else {
|
|
cte_cost = temp_table_info->table_plan_->get_cost();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < stmts.count(); i ++) {
|
|
ObLogPlan *plan = NULL;
|
|
ObSelectStmt *stmt = stmts.at(i);
|
|
ObLogicalOperator *best_plan = NULL;
|
|
if (OB_ISNULL(stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret));
|
|
} else if (OB_ISNULL(plan = ctx_.get_log_plan_factory().create(ctx_, *stmt))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("failed to create plan", "stmt", ctx_.get_query_ctx()->get_sql_stmt(), K(ret));
|
|
} else if (OB_FAIL(plan->generate_raw_plan())) {
|
|
LOG_WARN("failed to perform optimization", K(ret));
|
|
} else if (OB_FAIL(plan->init_candidate_plans(plan->get_candidate_plans().candidate_plans_))) {
|
|
LOG_WARN("failed to do candi into", K(ret));
|
|
} else if (OB_FAIL(plan->get_candidate_plans().get_best_plan(best_plan))) {
|
|
LOG_WARN("failed to get best plan", K(ret));
|
|
} else if (OB_FAIL(costs.push_back(best_plan->get_cost()))) {
|
|
LOG_WARN("failed to push back", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::generate_plan_for_temp_table(ObDMLStmt &stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIArray<ObSqlTempTableInfo*> &temp_table_infos = ctx_.get_temp_table_infos();
|
|
if (OB_FAIL(ObSqlTempTableInfo::collect_temp_tables(ctx_.get_allocator(), stmt, temp_table_infos,
|
|
ctx_.get_query_ctx(), true))) {
|
|
LOG_WARN("failed to add all temp tables", K(ret));
|
|
} else if (temp_table_infos.empty()) {
|
|
//do nothing
|
|
} else {
|
|
ObSqlTempTableInfo *temp_table_info = NULL;
|
|
ObSelectStmt *ref_query = NULL;
|
|
ObSelectLogPlan *temp_plan = NULL;
|
|
ObLogicalOperator *temp_op = NULL;
|
|
ObShardingInfo *sharding_info = NULL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < temp_table_infos.count(); i++) {
|
|
ObRawExpr *temp_table_nonwhere_filter = NULL;
|
|
ObRawExpr *temp_table_where_filter = NULL;
|
|
bool can_push_to_where = true;
|
|
if (OB_ISNULL(temp_table_info = temp_table_infos.at(i)) ||
|
|
OB_ISNULL(ref_query = temp_table_info->table_query_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(temp_table_info), K(ref_query));
|
|
} else if (OB_ISNULL(temp_plan = static_cast<ObSelectLogPlan*>
|
|
(ctx_.get_log_plan_factory().create(ctx_, *ref_query)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to create logical plan", K(temp_plan), K(ret));
|
|
} else if (OB_FALSE_IT(temp_plan->set_temp_table_info(temp_table_info))) {
|
|
} else {
|
|
OPT_TRACE_TITLE("begin generate plan for temp table ", temp_table_info->table_name_);
|
|
}
|
|
/**
|
|
* In table scan op, filters are calculated before `limit`.
|
|
* So, we can not push filter into temp table which contain `limit`.
|
|
*/
|
|
if (OB_FAIL(ret)) {
|
|
} else if (!ref_query->has_limit() &&
|
|
OB_FAIL(ObOptimizerUtil::try_push_down_temp_table_filter(ctx_,
|
|
*temp_table_info,
|
|
temp_table_nonwhere_filter,
|
|
temp_table_where_filter))) {
|
|
LOG_WARN("failed to push down filter for temp table", K(ret));
|
|
} else if (NULL != temp_table_where_filter &&
|
|
OB_FAIL(temp_plan->get_pushdown_filters().push_back(temp_table_where_filter))) {
|
|
LOG_WARN("failed to push down filter", K(ret));
|
|
} else if (OB_FAIL(temp_plan->generate_raw_plan())) {
|
|
LOG_WARN("Failed to generate temp_plan for sub_stmt", K(ret));
|
|
} else if (OB_FAIL(temp_plan->get_candidate_plans().get_best_plan(temp_op))) {
|
|
LOG_WARN("failed to get best plan", K(ret));
|
|
} else if (OB_FAIL(temp_plan->choose_duplicate_table_replica(temp_op,
|
|
ctx_.get_local_server_addr(),
|
|
true))) {
|
|
LOG_WARN("failed to choose duplicate table replica", K(ret));
|
|
} else if (OB_ISNULL(temp_op)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else {
|
|
sharding_info = temp_op->get_strong_sharding();
|
|
if (NULL != sharding_info && sharding_info->get_can_reselect_replica()) {
|
|
sharding_info->set_can_reselect_replica(false);
|
|
}
|
|
if (NULL != temp_table_nonwhere_filter) {
|
|
ObSEArray<ObRawExpr *, 1> expr_array;
|
|
if (OB_FAIL(expr_array.push_back(temp_table_nonwhere_filter))) {
|
|
LOG_WARN("failed to push back");
|
|
} else if (OB_FAIL(temp_plan->candi_allocate_filter(expr_array))) {
|
|
LOG_WARN("failed to push back", K(ret));
|
|
}
|
|
}
|
|
temp_table_info->table_plan_ = temp_op;
|
|
OPT_TRACE_TITLE("end generate plan for temp table ", temp_table_info->table_name_);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObOptimizer::exists_temp_table(const ObIArray<ObSqlTempTableInfo*> &temp_table_infos,
|
|
const ObSelectStmt *table_query) const
|
|
{
|
|
bool bret = false;
|
|
for (int64_t i = 0; !bret && i < temp_table_infos.count(); i++) {
|
|
bret = NULL != temp_table_infos.at(i) &&
|
|
temp_table_infos.at(i)->table_query_ == table_query;
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
int ObOptimizer::get_session_parallel_info(int64_t &force_parallel_dop,
|
|
bool &enable_auto_dop,
|
|
bool &enable_manual_dop)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
force_parallel_dop = ObGlobalHint::UNSET_PARALLEL;
|
|
enable_auto_dop = false;
|
|
enable_manual_dop = false;
|
|
ObSQLSessionInfo *session_info = NULL;
|
|
uint64_t session_force_dop = ObGlobalHint::UNSET_PARALLEL;
|
|
if (OB_ISNULL(session_info = ctx_.get_session_info())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(session_info), K(ret));
|
|
} else if (!session_info->is_user_session() && !session_info->get_ddl_info().is_refreshing_mview()) {
|
|
// sys var是依赖于schema的方式实现的,获得最新的sys var需要通过inner SQL的方式,会产生循环依赖
|
|
// 因此inner SQL情况下不考虑系统变量`SYS_VAR__ENABLE_PARALLEL_QUERY`的值
|
|
} else if (OB_FAIL(session_info->get_parallel_degree_policy_enable_auto_dop(enable_auto_dop))) {
|
|
LOG_WARN("failed to get sys variable for parallel degree policy", K(ret));
|
|
} else if (enable_auto_dop) {
|
|
/* do nothing */
|
|
} else if (!ctx_.can_use_pdml()) {
|
|
bool session_enable_parallel = false;
|
|
if (OB_FAIL(session_info->get_enable_parallel_query(session_enable_parallel))) {
|
|
LOG_WARN("failed to get sys variable for enable parallel query", K(ret));
|
|
} else if (OB_FAIL(session_info->get_force_parallel_query_dop(session_force_dop))) {
|
|
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
|
} else if (!session_enable_parallel) {
|
|
/* disable parallel */
|
|
} else if (ObGlobalHint::DEFAULT_PARALLEL < session_force_dop) {
|
|
force_parallel_dop = session_force_dop;
|
|
} else {
|
|
enable_manual_dop = true;
|
|
}
|
|
} else if (OB_FAIL(session_info->get_force_parallel_dml_dop(session_force_dop))) {
|
|
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
|
} else if (ObGlobalHint::DEFAULT_PARALLEL < session_force_dop) {
|
|
force_parallel_dop = session_force_dop;
|
|
} else if (OB_FAIL(session_info->get_force_parallel_query_dop(session_force_dop))) {
|
|
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
|
} else if (ObGlobalHint::DEFAULT_PARALLEL < session_force_dop) {
|
|
force_parallel_dop = session_force_dop;
|
|
} else {
|
|
enable_manual_dop = true;
|
|
}
|
|
|
|
LOG_TRACE("finish get parallel from session", K(ret), K(ctx_.can_use_pdml()), K(force_parallel_dop),
|
|
K(enable_auto_dop), K(enable_manual_dop));
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::check_dml_parallel_mode()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (ctx_.can_use_pdml() && ctx_.get_can_use_parallel_das_dml()) {
|
|
if (ctx_.get_global_hint().get_parallel_das_dml_option() == ObParallelDASOption::ENABLE) {
|
|
ctx_.set_can_use_pdml(false);
|
|
LOG_TRACE("parallel_das_dml hint cause force use das parallel");
|
|
} else {
|
|
ctx_.set_can_use_parallel_das_dml(false);
|
|
LOG_TRACE("pdml and parallel das dml all supported, choose pdml");
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::check_parallel_das_dml_supported_feature(const ObDelUpdStmt &pdml_stmt,
|
|
const ObSQLSessionInfo &session,
|
|
bool &use_parallel_das_dml)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (pdml_stmt.is_ignore()) {
|
|
use_parallel_das_dml = false;
|
|
} else if (ctx_.has_dblink()) {
|
|
use_parallel_das_dml = false;
|
|
LOG_TRACE("has dblink not use parallel das dml");
|
|
} else if (!ctx_.has_fk() && ctx_.contain_user_nested_sql()) {
|
|
use_parallel_das_dml = false;
|
|
LOG_TRACE("ctx has user nexted sql not use parallel das dml");
|
|
} else if (ctx_.is_online_ddl()) {
|
|
use_parallel_das_dml = false;
|
|
LOG_TRACE("is online ddl not use parallel das dml");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::check_parallel_das_dml_enabled(const ObDMLStmt &stmt,
|
|
ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool can_use_parallel_das_dml = true;
|
|
ObSqlCtx *sql_ctx = NULL;
|
|
ObQueryCtx *query_ctx = NULL;
|
|
bool session_enable_pdml = false;
|
|
bool session_enable_auto_dop = false;
|
|
uint64_t session_pdml_dop = ObGlobalHint::UNSET_PARALLEL;
|
|
|
|
if (OB_ISNULL(ctx_.get_exec_ctx()) || OB_ISNULL(query_ctx = ctx_.get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret), K(ctx_.get_exec_ctx()), K(query_ctx));
|
|
} else if (OB_ISNULL(sql_ctx = ctx_.get_exec_ctx()->get_sql_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret), K(ctx_.get_exec_ctx()));
|
|
} else if (!session.enable_parallel_das_dml()) {
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("enable_das_parallel_execution is false, can't submit task parallel");
|
|
} else if (!stmt.is_px_dml_supported_stmt()) {
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("stmt can't support parallel_das_dml");
|
|
} else if (ctx_.has_var_assign() && !ctx_.is_var_assign_only_in_root_stmt()) {
|
|
// It can be supported, but we won’t let it go for now and wait for the follow-up.
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("has var_assign, can't support parallel_das_dml now");
|
|
} else if (!session.is_user_session()) {
|
|
// not user request
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("not user request, can't support parallel_das_dml");
|
|
} else if (OB_FAIL(check_parallel_das_dml_supported_feature(static_cast<const ObDelUpdStmt&>(stmt),
|
|
session,
|
|
can_use_parallel_das_dml))) {
|
|
|
|
} else if (!can_use_parallel_das_dml) {
|
|
LOG_TRACE("not support parallel das dml");
|
|
} else if (ctx_.get_global_hint().get_parallel_das_dml_option() == ObParallelDASOption::DISABLE) {
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("hint force close das parallel, can't support parallel_das_dml");
|
|
} else if (query_ctx->get_query_hint().has_outline_data() &&
|
|
ctx_.get_global_hint().get_parallel_das_dml_option() != ObParallelDASOption::ENABLE) {
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("has outline data and hint disable, can't support parallel_das_dml",
|
|
K(ctx_.get_global_hint().get_parallel_das_dml_option()),
|
|
K(query_ctx->get_query_hint().has_outline_data()));
|
|
} else if (ctx_.can_use_pdml()) {
|
|
// can use pdml must can use parallel_das_dml
|
|
LOG_TRACE("pdml is enabled, can use parallel das");
|
|
} else if (ctx_.get_global_hint().get_pdml_option() == ObPDMLOption::ENABLE ||
|
|
ctx_.get_global_hint().get_parallel_das_dml_option() == ObParallelDASOption::ENABLE) {
|
|
LOG_TRACE("can use parallel_das_dml by pdml hint",
|
|
K(ctx_.get_global_hint().get_pdml_option()),
|
|
K(ctx_.get_global_hint().get_parallel_das_dml_option()));
|
|
} else if (ctx_.get_global_hint().enable_auto_dop()) {
|
|
// enable parallel das dml by auto dop hint
|
|
} else if (OB_FAIL(session.get_parallel_degree_policy_enable_auto_dop(session_enable_auto_dop))) {
|
|
LOG_WARN("failed to get sys variable for parallel degree policy", K(ret));
|
|
} else if (session_enable_auto_dop && !ctx_.get_global_hint().has_parallel_hint()) {
|
|
// session enable parallel dml by auto dop
|
|
} else if (OB_FAIL(session.get_enable_parallel_dml(session_enable_pdml))
|
|
|| OB_FAIL(session.get_force_parallel_dml_dop(session_pdml_dop))) {
|
|
LOG_WARN("failed to get sys variable for parallel dml", K(ret));
|
|
} else if (session_enable_pdml || ObGlobalHint::DEFAULT_PARALLEL < session_pdml_dop) {
|
|
// enable parallel das dml by session
|
|
} else {
|
|
can_use_parallel_das_dml = false;
|
|
LOG_TRACE("other scense, can't support parallel_das_dml");
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ctx_.set_can_use_parallel_das_dml(can_use_parallel_das_dml);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::check_pdml_enabled(const ObDMLStmt &stmt,
|
|
const ObSQLSessionInfo &session)
|
|
{
|
|
//
|
|
// 1. decided by enable_parallel_dml and disable_parallel_dml hint
|
|
// 2. decided by auto dop (by parallel(auto) hint or session variable parallel_degree_policy)
|
|
// 3. decided by session variable: _enable_parallel_dml is true or _force_parallel_dml_dop > 1;
|
|
int ret = OB_SUCCESS;
|
|
ObSqlCtx *sql_ctx = NULL;
|
|
ObQueryCtx *query_ctx = NULL;
|
|
bool can_use_pdml = true;
|
|
bool session_enable_pdml = false;
|
|
bool enable_auto_dop = false;
|
|
uint64_t session_pdml_dop = ObGlobalHint::UNSET_PARALLEL;
|
|
bool disable_pdml = false;
|
|
bool is_pk_auto_inc = false;
|
|
if (OB_ISNULL(ctx_.get_exec_ctx()) || OB_ISNULL(query_ctx = ctx_.get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret), K(ctx_.get_exec_ctx()), K(query_ctx));
|
|
} else if (OB_ISNULL(sql_ctx = ctx_.get_exec_ctx()->get_sql_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret), K(ctx_.get_exec_ctx()));
|
|
} else if (sql_ctx->is_batch_params_execute()) {
|
|
can_use_pdml = false;
|
|
// 当batch优化打开时,不支持pdml
|
|
} else if (!stmt.is_pdml_supported_stmt()) {
|
|
// pdml 支持新引擎和老引擎
|
|
// 3.1 及之前的版本,老引擎走 dml + px。3.2 起老引擎也能走 pdml
|
|
can_use_pdml = false;
|
|
} else if (ctx_.has_var_assign() && !ctx_.is_var_assign_only_in_root_stmt()) {
|
|
can_use_pdml = false;
|
|
} else if (stmt::T_INSERT == stmt.get_stmt_type() &&
|
|
OB_FAIL(static_cast< const ObInsertStmt &>(stmt).check_pdml_disabled(ctx_.is_online_ddl(),
|
|
disable_pdml,
|
|
is_pk_auto_inc))) {
|
|
LOG_WARN("fail to check pdml disabled for insert stmt", K(ret));
|
|
} else if (disable_pdml) {
|
|
can_use_pdml = false;
|
|
if (is_pk_auto_inc) {
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_INSERT_PK_AUTO_INC);
|
|
}
|
|
} else if (OB_FAIL(check_pdml_supported_feature(static_cast<const ObDelUpdStmt&>(stmt),
|
|
session, can_use_pdml))) {
|
|
LOG_WARN("failed to check pdml supported feature", K(ret));
|
|
} else if (!can_use_pdml || ctx_.is_online_ddl() ||
|
|
(stmt::T_INSERT == stmt.get_stmt_type() && static_cast< const ObInsertStmt &>(stmt).is_normal_table_overwrite())) {
|
|
// do nothing
|
|
} else if (ctx_.get_global_hint().get_pdml_option() == ObPDMLOption::ENABLE) {
|
|
// 1. enable parallel dml by hint
|
|
} else if (ctx_.get_global_hint().get_pdml_option() == ObPDMLOption::DISABLE
|
|
|| query_ctx->get_query_hint().has_outline_data()) {
|
|
can_use_pdml = false; // 1. disable parallel dml by hint
|
|
} else if (ctx_.get_global_hint().enable_auto_dop()) {
|
|
// 2.1 enable parallel dml by auto dop
|
|
} else if (session.is_user_session() &&
|
|
OB_FAIL(session.get_parallel_degree_policy_enable_auto_dop(enable_auto_dop))) {
|
|
LOG_WARN("failed to get sys variable for parallel degree policy", K(ret));
|
|
} else if (enable_auto_dop && !ctx_.get_global_hint().has_parallel_hint()) {
|
|
// 2.2 enable parallel dml by auto dop
|
|
} else if (!session.is_user_session()) {
|
|
can_use_pdml = false;
|
|
} else if (OB_FAIL(session.get_enable_parallel_dml(session_enable_pdml))
|
|
|| OB_FAIL(session.get_force_parallel_dml_dop(session_pdml_dop))) {
|
|
LOG_WARN("failed to get sys variable for parallel dml", K(ret));
|
|
} else if (session_enable_pdml || ObGlobalHint::DEFAULT_PARALLEL < session_pdml_dop) {
|
|
// 3. enable parallel dml by session
|
|
} else {
|
|
can_use_pdml = false;
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (can_use_pdml && OB_FAIL(check_is_heap_table(stmt))) {
|
|
LOG_WARN("failed to check is heap table", K(ret));
|
|
} else {
|
|
ctx_.set_can_use_pdml(can_use_pdml);
|
|
LOG_TRACE("check use all pdml feature", K(ret), K(can_use_pdml), K(ctx_.is_online_ddl()), K(session_enable_pdml));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// check pdml enable sql case
|
|
int ObOptimizer::check_pdml_supported_feature(const ObDelUpdStmt &pdml_stmt,
|
|
const ObSQLSessionInfo &session, bool &is_use_pdml)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
share::schema::ObSchemaGetterGuard *schema_guard = ctx_.get_schema_guard();
|
|
ObSEArray<const ObDmlTableInfo*, 2> table_infos;
|
|
// 依次检查被禁止的不稳定的功能,如果存在被禁止的不稳定功能 is open = false
|
|
if (OB_ISNULL(schema_guard)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("the schema guard is null", K(ret));
|
|
} else if (pdml_stmt.is_ignore()) {
|
|
is_use_pdml = false;
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_IGNORE);
|
|
} else if (OB_FAIL(pdml_stmt.get_dml_table_infos(table_infos))) {
|
|
LOG_WARN("failed to get dml table infos", K(ret));
|
|
} else if (table_infos.count() != 1) {
|
|
is_use_pdml = false;
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_JOINED_TABLES);
|
|
} else if (stmt::T_INSERT == pdml_stmt.get_stmt_type() &&
|
|
static_cast< const ObInsertStmt &>(pdml_stmt).is_insert_up()) {
|
|
is_use_pdml = false;
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_INSERT_UP);
|
|
} else if (pdml_stmt.is_pdml_disabled()) {
|
|
is_use_pdml = false;
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_TRANSFORMATIONS);
|
|
} else if (ctx_.has_dblink()) {
|
|
is_use_pdml = false;
|
|
} else if (ctx_.contain_user_nested_sql()) {
|
|
//user nested sql can't use PDML plan, force to use DAS plan
|
|
//if online ddl has pl udf, only this way, allow it use PDML plan
|
|
//such as:
|
|
//create table t1(a int primary key, b int as(udf()));
|
|
//create index i1 on t1(b);
|
|
//create index with PL UDF allow to use PDML plan during build index table
|
|
is_use_pdml = false;
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_NESTED_SQL);
|
|
} else if (stmt::T_DELETE == pdml_stmt.get_stmt_type()) {
|
|
//
|
|
// if no trigger, no foreign key, delete can do pdml, even if with local unique index
|
|
is_use_pdml = true;
|
|
} else if (!ctx_.is_online_ddl()) {
|
|
// check enabling parallel with local unique index
|
|
// 1. disable parallel insert. because parallel unique check not supported
|
|
// (storage does not support parallel unique check in one update/insert statement.)
|
|
// 2. disable parallel update. only if the unqiue column is updated.
|
|
// [FIXME] for now, we blindly disable PDML if table has unique local index
|
|
// 3. disable global index if main table has only one partition issue#35726194
|
|
//
|
|
// future work:
|
|
// data is reshuffled by partition key, so that same unique value may be reshuffled
|
|
// to different thread. To make same unique value reshuffled to same thread, we can
|
|
// do a hybrid reshuffle: map partition key to server, map unique key to thread.
|
|
// However, if there are more than one unique local index, this method will still fail.
|
|
uint64_t main_table_tid = table_infos.at(0)->ref_table_id_;
|
|
bool with_unique_local_idx = false;
|
|
if (OB_FAIL(schema_guard->check_has_local_unique_index(
|
|
session.get_effective_tenant_id(),
|
|
main_table_tid, with_unique_local_idx))) {
|
|
LOG_WARN("fail check if table with local unqiue index", K(main_table_tid), K(ret));
|
|
} else if (stmt::T_UPDATE == pdml_stmt.get_stmt_type()) {
|
|
for (int i = 0; OB_SUCC(ret) && is_use_pdml && i <
|
|
table_infos.at(0)->column_exprs_.count(); i++) {
|
|
ObColumnRefRawExpr* column_expr = table_infos.at(0)->column_exprs_.at(i);
|
|
if (column_expr->get_result_type().has_result_flag(ON_UPDATE_NOW_FLAG)) {
|
|
is_use_pdml = false;
|
|
ctx_.add_plan_note(PDML_DISABLED_BY_UPDATE_NOW);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::check_is_heap_table(const ObDMLStmt &stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *session = ctx_.get_session_info();
|
|
share::schema::ObSchemaGetterGuard *schema_guard = ctx_.get_schema_guard();
|
|
const share::schema::ObTableSchema *table_schema = NULL;
|
|
const ObDelUpdStmt *pdml_stmt = NULL;
|
|
ObSEArray<const ObDmlTableInfo*, 1> dml_table_infos;
|
|
// check if the target table is heap table
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(session));
|
|
} else if (ctx_.is_online_ddl()) {
|
|
ctx_.set_is_heap_table_ddl(session->get_ddl_info().is_heap_table_ddl());
|
|
} else if (NULL == (pdml_stmt = dynamic_cast<const ObDelUpdStmt*>(&stmt))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(pdml_stmt->get_dml_table_infos(dml_table_infos))) {
|
|
LOG_WARN("failed to get dml table infos", K(ret));
|
|
} else if (OB_UNLIKELY(dml_table_infos.count() != 1) || OB_ISNULL(dml_table_infos.at(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected dml table infos", K(ret), K(dml_table_infos));
|
|
} else if (OB_INVALID_ID == dml_table_infos.at(0)->ref_table_id_) {
|
|
// do nothing
|
|
} else if (OB_FAIL(schema_guard->get_table_schema(session->get_effective_tenant_id(),
|
|
dml_table_infos.at(0)->ref_table_id_,
|
|
table_schema))) {
|
|
LOG_WARN("failed to get table schema", K(ret));
|
|
} else if(OB_NOT_NULL(table_schema) && table_schema->is_heap_table()) {
|
|
ctx_.set_is_pdml_heap_table(true);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::init_env_info(ObDMLStmt &stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *session_info = NULL;
|
|
if (OB_ISNULL(session_info = ctx_.get_session_info())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(session_info), K(ret));
|
|
} else if (OB_FAIL(extract_column_usage_info(stmt))) {
|
|
LOG_WARN("failed to extract column usage info", K(ret));
|
|
} else if (OB_FAIL(extract_opt_ctx_basic_flags(stmt, *session_info))) {
|
|
LOG_WARN("fail to extract opt ctx basic flags", K(ret));
|
|
} else if (OB_FAIL(check_pdml_enabled(stmt, *session_info))) {
|
|
LOG_WARN("fail to check enable pdml", K(ret));
|
|
} else if (OB_FAIL(check_parallel_das_dml_enabled(stmt, *session_info))) {
|
|
LOG_WARN("fail to check enable parallel das dml", K(ret));
|
|
} else if (OB_FAIL(check_dml_parallel_mode())) {
|
|
LOG_WARN("fail to check force use parallel das dml", K(ret));
|
|
} else if (OB_FAIL(init_parallel_policy(stmt, *session_info))) { // call after check pdml enabled
|
|
LOG_WARN("fail to check enable pdml", K(ret));
|
|
} else if (OB_FAIL(init_replica_policy(stmt, *session_info))) {
|
|
LOG_WARN("fail to check enable column store replica", K(ret));
|
|
} else if (OB_FAIL(init_correlation_model(stmt, *session_info))) {
|
|
LOG_WARN("failed to init correlation model", K(ret));
|
|
} else if (OB_FAIL(init_table_access_policy(stmt, *session_info))) {
|
|
LOG_WARN("failed to init table access policy", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::extract_opt_ctx_basic_flags(const ObDMLStmt &stmt, ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool has_var_assign = false;
|
|
bool is_var_assign_only_in_root_stmt = false;
|
|
bool has_subquery_in_function_table = false;
|
|
bool has_dblink = false;
|
|
bool force_serial_set_order = false;
|
|
bool storage_estimation_enabled = false;
|
|
bool has_cursor_expr = false;
|
|
int64_t link_stmt_count = 0;
|
|
ObQueryCtx* query_ctx = ctx_.get_query_ctx();
|
|
bool push_join_pred_into_view_enabled = true;
|
|
bool partition_wise_plan_enabled = true;
|
|
bool exists_partition_wise_plan_enabled_hint = false;
|
|
omt::ObTenantConfigGuard tenant_config(TENANT_CONF(session.get_effective_tenant_id()));
|
|
bool rowsets_enabled = tenant_config.is_valid() && tenant_config->_rowsets_enabled;
|
|
ctx_.set_is_online_ddl(session.get_ddl_info().is_ddl()); // set is online ddl first, is used by other extract operations
|
|
bool das_keep_order_enabled = tenant_config.is_valid() && tenant_config->_enable_das_keep_order;
|
|
bool hash_join_enabled = tenant_config.is_valid() && tenant_config->_hash_join_enabled;
|
|
bool optimizer_sortmerge_join_enabled = tenant_config.is_valid() && tenant_config->_optimizer_sortmerge_join_enabled;
|
|
bool nested_loop_join_enabled = tenant_config.is_valid() && tenant_config->_nested_loop_join_enabled;
|
|
bool enable_adj_index_cost = false;
|
|
int64_t optimizer_index_cost_adj = 0;
|
|
bool is_skip_scan_enable = session.is_index_skip_scan_enabled();
|
|
bool enable_use_batch_nlj = false;
|
|
bool better_inlist_costing = false;
|
|
bool enable_spf_batch_rescan = session.is_spf_mlj_group_rescan_enabled();
|
|
bool enable_px_ordered_coord = GCONF._enable_px_ordered_coord;
|
|
const ObOptParamHint &opt_params = ctx_.get_global_hint().opt_params_;
|
|
if (OB_ISNULL(query_ctx)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get null query ctx");
|
|
} else if (OB_FAIL(check_whether_contain_nested_sql(stmt))) {
|
|
LOG_WARN("check whether contain nested sql failed", K(ret));
|
|
} else if (OB_FAIL(stmt.check_has_subquery_in_function_table(has_subquery_in_function_table))) {
|
|
LOG_WARN("failed to check stmt has function table", K(ret));
|
|
} else if (OB_FAIL(stmt.check_var_assign(has_var_assign, is_var_assign_only_in_root_stmt))) {
|
|
LOG_WARN("failed to check has ref assign user var", K(ret));
|
|
} else if (OB_FAIL(session.is_serial_set_order_forced(force_serial_set_order, lib::is_oracle_mode()))) {
|
|
LOG_WARN("fail to get force_serial_set_order", K(ret));
|
|
} else if (OB_FAIL(check_force_default_stat())) {
|
|
LOG_WARN("failed to check force default stat", K(ret));
|
|
} else if (OB_FAIL(init_system_stat())) {
|
|
LOG_WARN("failed to init system stat", K(ret));
|
|
} else if (OB_FAIL(calc_link_stmt_count(stmt, link_stmt_count))) {
|
|
LOG_WARN("calc link stmt count failed", K(ret));
|
|
} else if (OB_FAIL(ObDblinkUtils::has_reverse_link_or_any_dblink(&stmt, has_dblink, true))) {
|
|
LOG_WARN("failed to find dblink in stmt", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::ROWSETS_ENABLED, rowsets_enabled))) {
|
|
LOG_WARN("fail to check rowsets enabled", K(ret));
|
|
} else if (OB_FAIL(stmt.check_has_cursor_expression(has_cursor_expr))) {
|
|
LOG_WARN("fail to check cursor expression info", K(ret));
|
|
} else if (OB_FAIL(session.is_storage_estimation_enabled(storage_estimation_enabled))) {
|
|
LOG_WARN("fail to get storage_estimation_enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::ENABLE_DAS_KEEP_ORDER, das_keep_order_enabled))) {
|
|
LOG_WARN("failed to check das keep order enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::HASH_JOIN_ENABLED, hash_join_enabled))) {
|
|
LOG_WARN("failed to check hash join enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::OPTIMIZER_SORTMERGE_JOIN_ENABLED, optimizer_sortmerge_join_enabled))) {
|
|
LOG_WARN("failed to check merge join enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::NESTED_LOOP_JOIN_ENABLED, nested_loop_join_enabled))) {
|
|
LOG_WARN("failed to check nested loop join enabled", K(ret));
|
|
} else if (OB_FAIL(session.is_adj_index_cost_enabled(enable_adj_index_cost, optimizer_index_cost_adj))) {
|
|
LOG_WARN("failed to check adjust index cost", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_integer_opt_param(ObOptParamHint::OPTIMIZER_INDEX_COST_ADJ, optimizer_index_cost_adj))) {
|
|
LOG_WARN("fail to check opt param adjust index cost", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::OPTIMIZER_SKIP_SCAN_ENABLED, is_skip_scan_enable))) {
|
|
LOG_WARN("failed to get opt param skip scan enabled", K(ret));
|
|
} else if (OB_FAIL(session.is_better_inlist_enabled(better_inlist_costing))) {
|
|
LOG_WARN("failed to check better inlist enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::OPTIMIZER_BETTER_INLIST_COSTING, better_inlist_costing))) {
|
|
LOG_WARN("failed to get opt param better inlist costing", K(ret));
|
|
} else if (OB_FAIL(session.get_nlj_batching_enabled(enable_use_batch_nlj))) {
|
|
LOG_WARN("failed to get join cache size variable", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::NLJ_BATCHING_ENABLED, enable_use_batch_nlj))) {
|
|
LOG_WARN("failed to get opt param nlj batching enable", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::ENABLE_SPF_BATCH_RESCAN, enable_spf_batch_rescan))) {
|
|
LOG_WARN("failed to get opt param enable spf batch rescan", K(ret));
|
|
} else if (OB_FAIL(ctx_.get_global_hint().opt_params_.get_bool_opt_param(ObOptParamHint::_PUSH_JOIN_PREDICATE, push_join_pred_into_view_enabled))) {
|
|
LOG_WARN("fail to check rowsets enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::PARTITION_WISE_PLAN_ENABLED,
|
|
partition_wise_plan_enabled,
|
|
exists_partition_wise_plan_enabled_hint))) {
|
|
LOG_WARN("failed to check partition wise plan enabled", K(ret));
|
|
} else if (OB_FAIL(opt_params.get_bool_opt_param(ObOptParamHint::ENABLE_PX_ORDERED_COORD, enable_px_ordered_coord))) {
|
|
LOG_WARN("failed to get opt param enable px ordered coord", K(ret));
|
|
} else {
|
|
ctx_.init_batch_rescan_flags(enable_use_batch_nlj, enable_spf_batch_rescan,
|
|
query_ctx->optimizer_features_enable_version_);
|
|
ctx_.set_storage_estimation_enabled(storage_estimation_enabled);
|
|
ctx_.set_serial_set_order(force_serial_set_order);
|
|
ctx_.set_has_multiple_link_stmt(link_stmt_count > 1);
|
|
ctx_.set_has_var_assign(has_var_assign);
|
|
ctx_.set_is_var_assign_only_in_root_stmt(is_var_assign_only_in_root_stmt);
|
|
ctx_.set_has_subquery_in_function_table(has_subquery_in_function_table);
|
|
ctx_.set_has_dblink(has_dblink);
|
|
ctx_.set_cost_model_type(rowsets_enabled ? ObOptEstCost::VECTOR_MODEL : ObOptEstCost::NORMAL_MODEL);
|
|
ctx_.set_has_cursor_expression(has_cursor_expr);
|
|
ctx_.set_das_keep_order_enabled(GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_4_3_2_0 ? false : das_keep_order_enabled);
|
|
ctx_.set_optimizer_index_cost_adj(optimizer_index_cost_adj);
|
|
ctx_.set_is_skip_scan_enabled(is_skip_scan_enable);
|
|
ctx_.set_enable_better_inlist_costing(better_inlist_costing);
|
|
ctx_.set_push_join_pred_into_view_enabled(push_join_pred_into_view_enabled);
|
|
ctx_.set_enable_px_ordered_coord(enable_px_ordered_coord);
|
|
if (!hash_join_enabled
|
|
&& !optimizer_sortmerge_join_enabled
|
|
&& !nested_loop_join_enabled) {
|
|
ctx_.set_hash_join_enabled(true);
|
|
ctx_.set_merge_join_enabled(true);
|
|
ctx_.set_nested_join_enabled(true);
|
|
LOG_TRACE("all join types are set to disable");
|
|
} else {
|
|
ctx_.set_hash_join_enabled(hash_join_enabled);
|
|
ctx_.set_merge_join_enabled(optimizer_sortmerge_join_enabled);
|
|
ctx_.set_nested_join_enabled(nested_loop_join_enabled);
|
|
}
|
|
if (tenant_config.is_valid()) {
|
|
ctx_.set_partition_wise_plan_enabled(tenant_config->_partition_wise_plan_enabled);
|
|
}
|
|
if (exists_partition_wise_plan_enabled_hint) {
|
|
ctx_.set_partition_wise_plan_enabled(partition_wise_plan_enabled);
|
|
}
|
|
if (!session.is_inner() && stmt.get_query_ctx()->get_injected_random_status()) {
|
|
ctx_.set_generate_random_plan(true);
|
|
}
|
|
if (session.is_enable_new_query_range() &&
|
|
ObSQLUtils::is_min_cluster_version_ge_425_or_435() &&
|
|
ObSQLUtils::is_opt_feature_version_ge_425_or_435(query_ctx->optimizer_features_enable_version_)) {
|
|
ctx_.set_enable_new_query_range(true);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* parallel policy priority:
|
|
1. not support parallel: pl udf, dblink
|
|
2. global parallel hint:
|
|
a. force parallel dop: parallel(4)
|
|
b. auto dop: parallel(auto)
|
|
c. manual table dop: parallel(manual)
|
|
d. disable parallel: parallel(1) or no_parallel
|
|
3. session variable:
|
|
a. force parallel dop: _force_parallel_query_dop / _force_parallel_dml_dop > 1
|
|
b. auto dop: _enable_parallel_query / _enable_parallel_dml = 1,
|
|
_force_parallel_query_dop / _force_parallel_dml_dop = 1,
|
|
parallel_degree_policy = aoto
|
|
c. manual table dop: _enable_parallel_query / _enable_parallel_dml = 1,
|
|
_force_parallel_query_dop / _force_parallel_dml_dop = 1,
|
|
parallel_degree_policy = manual
|
|
d. disable parallel: _enable_parallel_query / _enable_parallel_dml = 0
|
|
*/
|
|
int ObOptimizer::init_parallel_policy(ObDMLStmt &stmt, const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ctx_.set_parallel(ObGlobalHint::DEFAULT_PARALLEL);
|
|
int64_t session_force_parallel_dop = ObGlobalHint::UNSET_PARALLEL;
|
|
bool session_enable_auto_dop = false;
|
|
bool session_enable_manual_dop = false;
|
|
if (OB_ISNULL(ctx_.get_query_ctx()) || OB_ISNULL(ctx_.get_exec_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query ctx is nul", K(ret));
|
|
} else if (ctx_.get_exec_ctx()->is_force_gen_local_plan()) {
|
|
ctx_.set_parallel_rule(PXParallelRule::PL_UDF_DAS_FORCE_SERIALIZE);
|
|
} else if (ctx_.has_pl_udf()) {
|
|
//following above rule, but if stmt contain pl_udf, force das, parallel should be 1
|
|
ctx_.set_parallel_rule(PXParallelRule::PL_UDF_DAS_FORCE_SERIALIZE);
|
|
} else if (ctx_.has_cursor_expression()) {
|
|
// if stmt contain cursor expression, cannot remote execute, force das, parallel should be 1
|
|
ctx_.set_parallel_rule(PXParallelRule::PL_UDF_DAS_FORCE_SERIALIZE);
|
|
} else if (ctx_.has_dblink()) {
|
|
//if stmt contain dblink, force das, parallel should be 1
|
|
ctx_.set_parallel_rule(PXParallelRule::DBLINK_FORCE_SERIALIZE);
|
|
} else if (ctx_.get_global_hint().has_parallel_degree()) {
|
|
ctx_.set_parallel_rule(PXParallelRule::MANUAL_HINT);
|
|
ctx_.set_parallel(ctx_.get_global_hint().get_parallel_degree());
|
|
} else if (ctx_.get_global_hint().enable_auto_dop()) {
|
|
ctx_.set_parallel_rule(PXParallelRule::AUTO_DOP);
|
|
} else if (ctx_.get_query_ctx()->get_query_hint().has_outline_data()) {
|
|
ctx_.set_parallel_rule(PXParallelRule::MANUAL_HINT);
|
|
ctx_.set_parallel(ObGlobalHint::DEFAULT_PARALLEL);
|
|
} else if (session.is_user_session() && !ctx_.get_global_hint().enable_manual_dop() &&
|
|
OB_FAIL(OB_E(EventTable::EN_ENABLE_AUTO_DOP_FORCE_PARALLEL_PLAN) OB_SUCCESS)) {
|
|
ret = OB_SUCCESS;
|
|
ctx_.set_parallel_rule(PXParallelRule::AUTO_DOP);
|
|
} else if (OB_FAIL(get_session_parallel_info(session_force_parallel_dop,
|
|
session_enable_auto_dop,
|
|
session_enable_manual_dop))) {
|
|
LOG_WARN("failed to get session parallel info", K(ret));
|
|
} else if (session_enable_auto_dop && !ctx_.get_global_hint().enable_manual_dop()) {
|
|
ctx_.set_parallel_rule(PXParallelRule::AUTO_DOP);
|
|
} else if (ObGlobalHint::UNSET_PARALLEL != session_force_parallel_dop) {
|
|
ctx_.set_parallel(session_force_parallel_dop);
|
|
ctx_.set_parallel_rule(PXParallelRule::SESSION_FORCE_PARALLEL);
|
|
} else if (session_enable_manual_dop || ctx_.get_global_hint().enable_manual_dop()) {
|
|
ctx_.set_parallel_rule(PXParallelRule::MANUAL_TABLE_DOP);
|
|
} else {
|
|
ctx_.set_parallel_rule(PXParallelRule::USE_PX_DEFAULT);
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (ctx_.is_use_auto_dop() && OB_FAIL(set_auto_dop_params(session))) {
|
|
LOG_WARN("failed to set auto dop params", K(ret));
|
|
} else {
|
|
LOG_TRACE("succeed to init parallel policy", K(session.is_user_session()),
|
|
K(ctx_.can_use_pdml()), K(ctx_.get_parallel_rule()), K(ctx_.get_parallel()),
|
|
K(ctx_.get_auto_dop_params()));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::init_replica_policy(ObDMLStmt &dml_stmt, const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t route_policy_type = 0;
|
|
if (OB_FAIL(session.get_sys_variable(SYS_VAR_OB_ROUTE_POLICY, route_policy_type))) {
|
|
LOG_WARN("fail to get sys variable", K(ret));
|
|
} else if (COLUMN_STORE_ONLY == static_cast<ObRoutePolicyType>(route_policy_type)) {
|
|
if (dml_stmt.get_query_ctx()->has_dml_write_stmt_ ||
|
|
dml_stmt.get_query_ctx()->is_contain_select_for_update_) {
|
|
ret = OB_NOT_SUPPORTED;
|
|
LOG_USER_ERROR(OB_NOT_SUPPORTED, "when route policy is COLUMN_STORE_ONLY, read query request");
|
|
} else {
|
|
ctx_.set_use_column_store_replica(true);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::init_correlation_model(ObDMLStmt &stmt, const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObEstCorrelationModel* correlation_model = NULL;
|
|
int64_t type = 0;
|
|
bool has_new_hint = false;
|
|
if (OB_ISNULL(ctx_.get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null ctx", K(ret));
|
|
} else if (!ctx_.get_query_ctx()->check_opt_compat_version(COMPAT_VERSION_4_2_4, COMPAT_VERSION_4_3_0,
|
|
COMPAT_VERSION_4_3_3)) {
|
|
type = static_cast<int64_t>(ObEstCorrelationType::INDEPENDENT);
|
|
} else if (OB_FAIL(ctx_.get_global_hint().opt_params_.has_opt_param(ObOptParamHint::CARDINALITY_ESTIMATION_MODEL, has_new_hint))) {
|
|
LOG_WARN("failed to check whether has hint param", K(ret));
|
|
} else {
|
|
/**
|
|
* 'cardinality_estimation_model' is same as the name of the system variable.
|
|
* 'correlation_for_cardinality_estimation' should be deprecated.
|
|
* So the former has a higher priority.
|
|
*/
|
|
ObOptParamHint::OptParamType opt_param_type = ObOptParamHint::CORRELATION_FOR_CARDINALITY_ESTIMATION;
|
|
if (has_new_hint) {
|
|
opt_param_type = ObOptParamHint::CARDINALITY_ESTIMATION_MODEL;
|
|
}
|
|
if (OB_FAIL(ctx_.get_global_hint().opt_params_.get_enum_sys_var(opt_param_type,
|
|
&session,
|
|
share::SYS_VAR_CARDINALITY_ESTIMATION_MODEL,
|
|
type))) {
|
|
LOG_WARN("failed to get hint param", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_UNLIKELY(type < 0) ||
|
|
OB_UNLIKELY(type >= static_cast<int64_t>(ObEstCorrelationType::MAX))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected correlation type", K(type));
|
|
} else {
|
|
ctx_.set_correlation_type(static_cast<ObEstCorrelationType>(type));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::init_table_access_policy(ObDMLStmt &stmt, const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t policy = 0;
|
|
bool has_hint = false;
|
|
if (OB_ISNULL(ctx_.get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null ctx", K(ret));
|
|
} else if (OB_FAIL(ctx_.get_global_hint().opt_params_.has_opt_param(ObOptParamHint::OB_TABLE_ACCESS_POLICY, has_hint))) {
|
|
LOG_WARN("failed to check whether has hint param", K(ret));
|
|
} else if (has_hint) {
|
|
if (OB_FAIL(ctx_.get_global_hint().opt_params_.get_enum_opt_param(ObOptParamHint::OB_TABLE_ACCESS_POLICY, policy))) {
|
|
LOG_WARN("failed to get enum hint param", K(ret));
|
|
}
|
|
} else if (OB_FAIL(session.get_sys_variable(share::SYS_VAR_OB_TABLE_ACCESS_POLICY, policy))) {
|
|
LOG_WARN("failed to get sys variable", K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_UNLIKELY(policy < 0) ||
|
|
OB_UNLIKELY(policy >= static_cast<int64_t>(ObTableAccessPolicy::MAX))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected table access polisy", K(policy));
|
|
} else {
|
|
ctx_.set_table_access_policy(static_cast<ObTableAccessPolicy>(policy));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::set_auto_dop_params(const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint64_t parallel_degree_limit = 0;
|
|
uint64_t parallel_min_scan_time_threshold = 1000;
|
|
AutoDOPParams params;
|
|
if (!session.is_user_session()) {
|
|
/* do nothing */
|
|
} else if (OB_FAIL(session.get_sys_variable(share::SYS_VAR_PARALLEL_DEGREE_LIMIT, parallel_degree_limit))) {
|
|
LOG_WARN("failed to get sys variable parallel degree limit", K(ret));
|
|
} else if (OB_FAIL(session.get_sys_variable(share::SYS_VAR_PARALLEL_MIN_SCAN_TIME_THRESHOLD, parallel_min_scan_time_threshold))) {
|
|
LOG_WARN("failed to get sys variable parallel threshold", K(ret));
|
|
}
|
|
|
|
if (OB_SUCC(ret) && 0 == parallel_degree_limit) {
|
|
const ObTenantBase *tenant = NULL;
|
|
int64_t parallel_servers_target = 0;
|
|
if (OB_ISNULL(tenant = MTL_CTX())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret));
|
|
} else if (session.is_user_session() &&
|
|
OB_FAIL(ObSchemaUtils::get_tenant_int_variable(session.get_effective_tenant_id(),
|
|
SYS_VAR_PARALLEL_SERVERS_TARGET,
|
|
parallel_servers_target))) {
|
|
LOG_WARN("fail read tenant variable", K(ret), K(session.get_effective_tenant_id()));
|
|
} else {
|
|
params.unit_min_cpu_ = std::max(tenant->unit_min_cpu(), 0.0);
|
|
params.parallel_servers_target_ = std::max(parallel_servers_target, 0L);
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
params.parallel_min_scan_time_threshold_ = parallel_min_scan_time_threshold;
|
|
params.parallel_degree_limit_ = parallel_degree_limit;
|
|
ctx_.set_auto_dop_params(params);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//to check whether contain trigger, foreign key, PL UDF or this sql is triggered by these object
|
|
int ObOptimizer::check_whether_contain_nested_sql(const ObDMLStmt &stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObDelUpdStmt *del_upd_stmt = nullptr;
|
|
// dml + select need run das path
|
|
if (!stmt.get_query_ctx()->disable_udf_parallel_ && stmt.get_query_ctx()->udf_has_select_stmt_) {
|
|
stmt.get_query_ctx()->disable_udf_parallel_ |= ((stmt.is_select_stmt() && stmt.has_for_update())
|
|
|| (stmt.is_dml_write_stmt()));
|
|
}
|
|
if (stmt.get_query_ctx()->disable_udf_parallel_) {
|
|
ctx_.set_has_pl_udf(true);
|
|
}
|
|
if (ObSQLUtils::is_nested_sql(ctx_.get_exec_ctx())) {
|
|
ctx_.set_in_nested_sql(true);
|
|
}
|
|
if ((del_upd_stmt = dynamic_cast<const ObDelUpdStmt*>(&stmt)) != nullptr) {
|
|
ObSEArray<const ObDmlTableInfo*,2> table_infos;
|
|
if (OB_FAIL(del_upd_stmt->get_dml_table_infos(table_infos))) {
|
|
LOG_WARN("failed to get dml table infos", K(ret));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < table_infos.count(); ++i) {
|
|
const ObDmlTableInfo* table_info = table_infos.at(i);
|
|
ObSchemaGetterGuard *schema_guard = ctx_.get_schema_guard();
|
|
const ObTableSchema *table_schema = nullptr;
|
|
ObSQLSessionInfo *session = ctx_.get_session_info();
|
|
bool trigger_exists = false;
|
|
if (OB_ISNULL(table_info) || OB_ISNULL(schema_guard) || OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("sql schema guard is nullptr", K(ret), K(table_info), K(schema_guard), K(session));
|
|
} else if (OB_FAIL(schema_guard->get_table_schema(session->get_effective_tenant_id(),
|
|
table_info->ref_table_id_, table_schema))) {
|
|
LOG_WARN("get table schema failed", K(ret), K(table_info->ref_table_id_));
|
|
} else if (!table_schema->get_foreign_key_infos().empty()) {
|
|
ctx_.set_has_fk(true);
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(table_schema->check_has_trigger_on_table(*schema_guard,
|
|
trigger_exists,
|
|
del_upd_stmt->get_trigger_events()))) {
|
|
LOG_WARN("check has trigger on table failed", K(ret));
|
|
} else if (trigger_exists) {
|
|
ctx_.set_has_trigger(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::calc_link_stmt_count(const ObDMLStmt &stmt, int64_t &count)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (stmt.is_dblink_stmt()) {
|
|
count += 1;
|
|
} else {
|
|
ObSEArray<ObSelectStmt *, 4> child_stmts;
|
|
if (OB_FAIL(stmt.get_child_stmts(child_stmts))) {
|
|
LOG_WARN("failed to get child stmts", K(ret));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
|
|
if (OB_ISNULL(child_stmts.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(calc_link_stmt_count(*child_stmts.at(i), count)))) {
|
|
LOG_WARN("failed to extract column usage info", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
const common::ObIArray<TableItem*> &table_items = stmt.get_table_items();
|
|
for (int64_t i = 0; i < table_items.count() && OB_SUCC(ret); i++) {
|
|
const TableItem *table_item = table_items.at(i);
|
|
if (OB_ISNULL(table_item)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get null ptr", K(ret));
|
|
} else if (table_item->is_temp_table()) {
|
|
if (OB_ISNULL(table_item->ref_query_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get null ptr", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(calc_link_stmt_count(*table_item->ref_query_, count)))) {
|
|
LOG_WARN("failed to extract column usage info", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::extract_column_usage_info(const ObDMLStmt &stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSEArray<ObSelectStmt *, 4> child_stmts;
|
|
ObSEArray<ObRawExpr *, 32> condition_exprs;
|
|
if (OB_FAIL(stmt.get_child_stmts(child_stmts))) {
|
|
LOG_WARN("failed to get child stmts", K(ret));
|
|
} else if (OB_FAIL(stmt.get_where_scope_conditions(condition_exprs))) {
|
|
LOG_WARN("failed to get where scope conditions", K(ret));
|
|
} else if (stmt.is_select_stmt() &&
|
|
OB_FAIL(append(condition_exprs, static_cast<const ObSelectStmt&>(stmt).get_having_exprs()))) {
|
|
LOG_WARN("failed to append", K(ret));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
|
|
if (OB_ISNULL(child_stmts.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(extract_column_usage_info(*child_stmts.at(i))))) {
|
|
LOG_WARN("failed to extract column usage info", K(ret));
|
|
}
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < condition_exprs.count(); ++i) {
|
|
if (OB_FAIL(analyze_one_expr(stmt, condition_exprs.at(i)))) {
|
|
LOG_WARN("failed to analyze one expr", K(ret));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && stmt.is_select_stmt()) {
|
|
const ObSelectStmt &sel_stmt = static_cast<const ObSelectStmt &>(stmt);
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt.get_group_expr_size(); ++i) {
|
|
const ObRawExpr *expr = sel_stmt.get_group_exprs().at(i);
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (expr->is_column_ref_expr()) {
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(expr)),
|
|
ColumnUsageFlag::GROUPBY_MEMBER);
|
|
}
|
|
}
|
|
if (sel_stmt.is_distinct() && !sel_stmt.is_set_stmt()) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt.get_select_item_size(); ++i) {
|
|
const ObRawExpr *expr = sel_stmt.get_select_item(i).expr_;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (expr->is_column_ref_expr()) {
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(expr)),
|
|
ColumnUsageFlag::DISTINCT_MEMBER);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::analyze_one_expr(const ObDMLStmt &stmt, const ObRawExpr *expr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (expr->get_expr_type() == T_OP_OR || expr->get_expr_type() == T_OP_AND) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
|
|
if (OB_FAIL(analyze_one_expr(stmt, expr->get_param_expr(i)))) {
|
|
LOG_WARN("failed to analyze one expr", K(ret));
|
|
}
|
|
}
|
|
} else if (expr->get_expr_type() == T_OP_IS || expr->get_expr_type() == T_OP_IS_NOT) {
|
|
const ObRawExpr *left_expr = expr->get_param_expr(0);
|
|
const ObRawExpr *right_expr = expr->get_param_expr(1);
|
|
if (OB_ISNULL(left_expr) || OB_ISNULL(right_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (left_expr->is_column_ref_expr() && T_NULL == right_expr->get_expr_type()) {
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(left_expr)),
|
|
ColumnUsageFlag::NULL_PREDS);
|
|
}
|
|
} else if (expr->get_expr_type() == T_OP_LIKE) {
|
|
const ObRawExpr *left_expr = expr->get_param_expr(0);
|
|
if (OB_ISNULL(left_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (left_expr->is_column_ref_expr()) {
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(left_expr)),
|
|
ColumnUsageFlag::LIKE_PREDS);
|
|
}
|
|
} else if (expr->get_expr_type() == T_OP_EQ || expr->get_expr_type() == T_OP_NSEQ) {
|
|
const ObRawExpr *left_expr = expr->get_param_expr(0);
|
|
const ObRawExpr *right_expr = expr->get_param_expr(1);
|
|
if (OB_ISNULL(left_expr) || OB_ISNULL(right_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (left_expr->is_column_ref_expr() && right_expr->is_column_ref_expr()) {
|
|
if (OB_FAIL(add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(left_expr)),
|
|
ColumnUsageFlag::EQUIJOIN_PREDS))) {
|
|
LOG_WARN("failed to add column usage arg", K(ret), K(*expr));
|
|
} else if (OB_FAIL(add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(right_expr)),
|
|
ColumnUsageFlag::EQUIJOIN_PREDS))) {
|
|
LOG_WARN("failed to add column usage arg", K(ret));
|
|
}
|
|
} else if (left_expr->is_column_ref_expr() || right_expr->is_column_ref_expr()) {
|
|
const ObRawExpr *column_expr = left_expr->is_column_ref_expr() ? left_expr :right_expr;
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(column_expr)),
|
|
ColumnUsageFlag::EQUALITY_PREDS);
|
|
} else { /*do nothing*/ }
|
|
} else if (expr->get_expr_type() == T_OP_IN || expr->get_expr_type() == T_OP_NOT_IN) {
|
|
const ObRawExpr *left_expr = expr->get_param_expr(0);
|
|
if (OB_ISNULL(left_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (left_expr->is_column_ref_expr()) {
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(left_expr)),
|
|
ColumnUsageFlag::EQUALITY_PREDS);
|
|
}
|
|
} else if (IS_COMMON_COMPARISON_OP(expr->get_expr_type())) {
|
|
const ObRawExpr *left_expr = expr->get_param_expr(0);
|
|
const ObRawExpr *right_expr = expr->get_param_expr(1);
|
|
if (OB_ISNULL(left_expr) || OB_ISNULL(right_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (left_expr->is_column_ref_expr() && right_expr->is_column_ref_expr()) {
|
|
if (OB_FAIL(add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(left_expr)),
|
|
ColumnUsageFlag::EQUIJOIN_PREDS))) {
|
|
LOG_WARN("failed to add column usage arg", K(ret));
|
|
} else if (OB_FAIL(add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(right_expr)),
|
|
ColumnUsageFlag::NONEQUIJOIN_PREDS))) {
|
|
LOG_WARN("failed to add column usage arg", K(ret));
|
|
}
|
|
} else if (left_expr->is_column_ref_expr() || right_expr->is_column_ref_expr()) {
|
|
const ObRawExpr *column_expr = left_expr->is_column_ref_expr() ? left_expr :right_expr;
|
|
ret = add_column_usage_arg(stmt,
|
|
*(static_cast<const ObColumnRefRawExpr *>(column_expr)),
|
|
ColumnUsageFlag::RANGE_PREDS);
|
|
} else { /*do nothing*/ }
|
|
} else if (expr->get_expr_type() == T_OP_BTW || expr->get_expr_type() == T_OP_NOT_BTW) {
|
|
// now between has been rewrote to >= and <= at resolver phase
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::add_column_usage_arg(const ObDMLStmt &stmt,
|
|
const ObColumnRefRawExpr &column_expr,
|
|
int64_t flag)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const TableItem *table = stmt.get_table_item_by_id(column_expr.get_table_id());
|
|
if (OB_ISNULL(table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected NULL", K(ret), K(column_expr), K(table), K(stmt.get_table_items()));
|
|
} else if (table->is_basic_table()) {
|
|
bool find = false;
|
|
for (int64_t i = 0; i < ctx_.get_column_usage_infos().count(); ++i) {
|
|
if (ctx_.get_column_usage_infos().at(i).table_id_ == table->ref_id_ &&
|
|
ctx_.get_column_usage_infos().at(i).column_id_ == column_expr.get_column_id()) {
|
|
ctx_.get_column_usage_infos().at(i).flags_ |= flag;
|
|
}
|
|
}
|
|
if (!find) {
|
|
ColumnUsageArg col_arg;
|
|
col_arg.table_id_ = table->ref_id_;
|
|
col_arg.column_id_ = column_expr.get_column_id();
|
|
col_arg.flags_ = flag;
|
|
ret = ctx_.get_column_usage_infos().push_back(col_arg);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::update_column_usage_infos()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *session = ctx_.get_session_info();
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(session));
|
|
} else {
|
|
MTL_SWITCH(session->get_effective_tenant_id()) {
|
|
ObOptStatMonitorManager *optstat_monitor_mgr = NULL;
|
|
if (OB_ISNULL(optstat_monitor_mgr = MTL(ObOptStatMonitorManager*))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(optstat_monitor_mgr));
|
|
} else if (OB_FAIL(optstat_monitor_mgr->update_local_cache(ctx_.get_column_usage_infos()))) {
|
|
LOG_WARN("failed to update local cache", K(ret));
|
|
} else {/*do nothing*/}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::check_force_default_stat()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
share::schema::ObSchemaGetterGuard* schema_guard = ctx_.get_schema_guard();
|
|
ObSQLSessionInfo* session = ctx_.get_session_info();
|
|
ObQueryCtx* query_ctx = ctx_.get_query_ctx();
|
|
bool is_restore = false;
|
|
bool use_default_opt_stat = false;
|
|
bool is_exists_opt = false;
|
|
if (OB_ISNULL(schema_guard) || OB_ISNULL(session) || OB_ISNULL(query_ctx)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(schema_guard), K(session), K(query_ctx));
|
|
} else if (OB_FAIL(schema_guard->check_tenant_is_restore(session->get_effective_tenant_id(),
|
|
is_restore))) {
|
|
LOG_WARN("fail to check if tenant is restore", K(session->get_effective_tenant_id()));
|
|
} else if (is_restore) {
|
|
// 为避免物理恢复阶段系统表恢复过程中,SQL依赖需要恢复的统计信息表,
|
|
// 对恢复中租户,仅需获取缺省统计信息即可
|
|
ctx_.set_use_default_stat();
|
|
} else if (query_ctx->get_global_hint().has_dbms_stats_hint()) {
|
|
ctx_.set_use_default_stat();
|
|
} else if (OB_FAIL(query_ctx->get_global_hint().opt_params_.get_bool_opt_param(ObOptParamHint::USE_DEFAULT_OPT_STAT,
|
|
use_default_opt_stat,
|
|
is_exists_opt))) {
|
|
LOG_WARN("fail to check use default opt stat", K(ret));
|
|
} else if (is_exists_opt && use_default_opt_stat) {
|
|
ctx_.set_use_default_stat();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObOptimizer::init_system_stat()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_valid = false;
|
|
OptSystemStat &meta = ctx_.get_system_stat();
|
|
ObOptStatManager *opt_stat_manager = ctx_.get_opt_stat_manager();
|
|
ObSQLSessionInfo* session = ctx_.get_session_info();
|
|
if (OB_ISNULL(opt_stat_manager) || OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null param", K(ret));
|
|
} else if (OB_FAIL(opt_stat_manager->check_system_stat_validity(ctx_.get_exec_ctx(),
|
|
session->get_effective_tenant_id(),
|
|
is_valid))) {
|
|
LOG_WARN("failed to check system stat is valid", K(ret));
|
|
} else if (!ctx_.use_default_stat() && is_valid) {
|
|
ObOptSystemStat stat;
|
|
if (OB_FAIL(opt_stat_manager->get_system_stat(session->get_effective_tenant_id(), stat))) {
|
|
LOG_WARN("failed to get system stat", K(ret));
|
|
} else {
|
|
meta.set_cpu_speed(stat.get_cpu_speed());
|
|
meta.set_disk_seq_read_speed(stat.get_disk_seq_read_speed());
|
|
meta.set_disk_rnd_read_speed(stat.get_disk_rnd_read_speed());
|
|
meta.set_network_speed(stat.get_network_speed());
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
//refine default stat
|
|
if (meta.get_cpu_speed() <= 0) {
|
|
meta.set_cpu_speed(DEFAULT_CPU_SPEED);
|
|
}
|
|
if (meta.get_disk_seq_read_speed() <= 0) {
|
|
meta.set_disk_seq_read_speed(DEFAULT_DISK_SEQ_READ_SPEED);
|
|
}
|
|
if (meta.get_disk_rnd_read_speed() <= 0) {
|
|
meta.set_disk_rnd_read_speed(DEFAULT_DISK_RND_READ_SPEED);
|
|
}
|
|
if (meta.get_network_speed() <= 0) {
|
|
meta.set_network_speed(DEFAULT_NETWORK_SPEED);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|