[FEAT MERGE] support auto dop
This commit is contained in:
@ -237,246 +237,135 @@ bool ObOptimizer::exists_temp_table(const ObIArray<ObSqlTempTableInfo*> &temp_ta
|
||||
return bret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the attr from stmt recursively object
|
||||
*
|
||||
* @param stmt
|
||||
* @param max_dop used for table's parallel attribute
|
||||
* @param max_table_parallel used for parallelism at the statement or object level
|
||||
* @return int
|
||||
*/
|
||||
int ObOptimizer::get_stmt_parallel_info(ObDMLStmt *stmt,
|
||||
int64_t &max_table_dop,
|
||||
int64_t &max_table_parallel)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObSEArray<ObSelectStmt*, 4> child_stmts;
|
||||
int64_t cur_max_table_hint = ObGlobalHint::UNSET_PARALLEL;
|
||||
if (OB_ISNULL(stmt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else if (OB_FAIL(stmt->get_child_stmts(child_stmts))) {
|
||||
LOG_WARN("failed to get child stmt", K(ret));
|
||||
} else if (OB_FAIL(SMART_CALL(get_stmt_max_table_dop(*stmt, max_table_dop)))) {
|
||||
LOG_WARN("failed to get stmt max table dop", K(ret));
|
||||
} else if (OB_FAIL(stmt->get_stmt_hint().get_max_table_parallel(*stmt, cur_max_table_hint))) {
|
||||
LOG_WARN("failed to get max table parallel", K(ret));
|
||||
} else {
|
||||
max_table_parallel = std::max(max_table_parallel, cur_max_table_hint);
|
||||
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(get_stmt_parallel_info(child_stmts.at(i),
|
||||
max_table_dop,
|
||||
max_table_parallel)))) {
|
||||
LOG_WARN("failed to get stmt max table dop", K(ret));
|
||||
} else { /*do nothing*/ }
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObOptimizer::get_stmt_max_table_dop(ObDMLStmt &stmt,
|
||||
int64_t &max_table_dop)
|
||||
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;
|
||||
share::schema::ObSchemaGetterGuard *schema_guard = ctx_.get_schema_guard();
|
||||
if (OB_ISNULL(schema_guard) ||
|
||||
OB_ISNULL(session_info = ctx_.get_session_info())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(schema_guard), K(session_info), K(ret));
|
||||
} else {
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_table_items().count(); i++) {
|
||||
TableItem *table_item = NULL;
|
||||
const share::schema::ObTableSchema *table_schema = NULL;
|
||||
if (OB_ISNULL(table_item = stmt.get_table_items().at(i))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else if (table_item->is_function_table() ||
|
||||
table_item->is_json_table() ||
|
||||
table_item->is_link_table() ||
|
||||
table_item->is_fake_cte_table() ||
|
||||
table_item->is_joined_table()) {
|
||||
} else if (table_item->is_temp_table()) {
|
||||
if (OB_FAIL(SMART_CALL(get_stmt_max_table_dop(*table_item->ref_query_, max_table_dop)))) {
|
||||
LOG_WARN("failed to get max table dop from ref query", K(ret));
|
||||
}
|
||||
} else if (table_item->is_generated_table()) {
|
||||
} else {
|
||||
uint64_t tids[OB_MAX_INDEX_PER_TABLE + 1];
|
||||
int64_t index_count = OB_MAX_INDEX_PER_TABLE + 1;
|
||||
const bool with_global_index = true;
|
||||
const bool with_mv = false;
|
||||
//FIXME: can't get tenant_id from table_id
|
||||
const uint64_t tenant_id = session_info->get_effective_tenant_id();
|
||||
if (OB_FAIL(schema_guard->get_can_read_index_array(tenant_id,
|
||||
table_item->ref_id_,
|
||||
tids,
|
||||
index_count,
|
||||
with_mv,
|
||||
with_global_index,
|
||||
false /*domain index*/))) {
|
||||
LOG_WARN("failed to get can read index", K(tenant_id), K(table_item->ref_id_), K(ret));
|
||||
} else if (OB_UNLIKELY(index_count > OB_MAX_INDEX_PER_TABLE + 1)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid index count", K(table_item->ref_id_), K(index_count), K(ret));
|
||||
} else {
|
||||
for (int64_t i = -1; OB_SUCC(ret) && i < index_count; ++i) {
|
||||
const uint64_t tid = (i == -1) ? table_item->ref_id_: tids[i]; //with base table
|
||||
if (OB_FAIL(schema_guard->get_table_schema(
|
||||
session_info->get_effective_tenant_id(), tid, table_schema))) {
|
||||
LOG_WARN("failed to get table schema", K(ret));
|
||||
} else if (OB_ISNULL(table_schema)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret), K(lbt()));
|
||||
} else {
|
||||
max_table_dop = std::max(max_table_dop, table_schema->get_dop());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObOptimizer::get_session_parallel_info(ObDMLStmt &stmt,
|
||||
bool use_pdml,
|
||||
bool &session_enable_parallel,
|
||||
uint64_t &session_force_parallel_dop)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObSQLSessionInfo *session_info = NULL;
|
||||
session_enable_parallel = false;
|
||||
session_force_parallel_dop = 1;
|
||||
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()) {
|
||||
} else if (!session_info->is_user_session()) {
|
||||
// sys var是依赖于schema的方式实现的,获得最新的sys var需要通过inner SQL的方式,会产生循环依赖
|
||||
// 因此inner SQL情况下不考虑系统变量`SYS_VAR__ENABLE_PARALLEL_QUERY`的值
|
||||
if (!stmt.is_px_dml_supported_stmt()) {
|
||||
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_parallel_dop))) {
|
||||
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
||||
}
|
||||
} 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 {
|
||||
// DML 情况比较特殊:
|
||||
// 如果是 PX+DML 模式,那么并发度应该是读取 query 的,
|
||||
// 而不是 force dml parallel 的值
|
||||
if (use_pdml) {
|
||||
if (OB_FAIL(session_info->get_enable_parallel_dml(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_dml_dop(session_force_parallel_dop))) {
|
||||
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
||||
} else if (session_force_parallel_dop == 1) {
|
||||
// 此时是 ENABLE_PARALLEL_DML HINT + FORCE PARALLEL QUERY 的组合
|
||||
// session_force_parallel_dop 需要填 Query 的 dop
|
||||
if (OB_FAIL(session_info->get_force_parallel_query_dop(session_force_parallel_dop))) {
|
||||
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
||||
} else { /*do nothing*/ }
|
||||
}
|
||||
} else {
|
||||
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_parallel_dop))) {
|
||||
LOG_WARN("failed to get sys variable for force parallel query dop", K(ret));
|
||||
} else { /*do nothing*/ }
|
||||
}
|
||||
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_pdml_enabled(const ObDMLStmt &stmt,
|
||||
const ObSQLSessionInfo &session,
|
||||
bool &is_use_pdml)
|
||||
const ObSQLSessionInfo &session)
|
||||
{
|
||||
//
|
||||
// 1. pdml: force parallel dml & no DISABLE_PARALLEL_DML hint
|
||||
// 2. enable parallel query: parallel hint | sess enable_parallel_query
|
||||
// pdml: enable parallel dml + enable parallel query
|
||||
// 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;
|
||||
uint64_t force_pdml_dop = 1;
|
||||
ObSqlCtx *sql_ctx = NULL;
|
||||
is_use_pdml = false;
|
||||
// case 1
|
||||
if (OB_ISNULL(ctx_.get_query_ctx())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected null", K(ret), K(ctx_.get_query_ctx()));
|
||||
} else if (OB_ISNULL(ctx_.get_exec_ctx())) {
|
||||
bool can_use_pdml = true;
|
||||
bool session_enable_pdml = false;
|
||||
bool enable_auto_dop = false;
|
||||
uint64_t session_pdml_dop = ObGlobalHint::UNSET_PARALLEL;
|
||||
if (OB_ISNULL(ctx_.get_exec_ctx())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected null", K(ret), K(ctx_.get_exec_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->multi_stmt_item_.is_batched_multi_stmt()) {
|
||||
is_use_pdml = false;
|
||||
can_use_pdml = false;
|
||||
// 当batch优化打开时,不支持pdml
|
||||
} else if (!stmt.is_pdml_supported_stmt()) {
|
||||
// pdml 支持新引擎和老引擎
|
||||
// 3.1 及之前的版本,老引擎走 dml + px。3.2 起老引擎也能走 pdml
|
||||
is_use_pdml = false;
|
||||
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() &&
|
||||
!static_cast< const ObInsertStmt &>(stmt).value_from_select()) {
|
||||
is_use_pdml = false;
|
||||
can_use_pdml = false;
|
||||
} else if ((stmt.is_update_stmt() || stmt.is_delete_stmt())
|
||||
&& static_cast<const ObDelUpdStmt &>(stmt).is_dml_table_from_join()) {
|
||||
is_use_pdml = false;
|
||||
} else if (OB_FAIL(session.get_force_parallel_dml_dop(force_pdml_dop))) {
|
||||
LOG_WARN("fail get force parallel dml session val", K(ret));
|
||||
} else if (force_pdml_dop > 1) {
|
||||
const ObGlobalHint &global_hint = stmt.get_query_ctx()->get_global_hint();
|
||||
if (global_hint.get_pdml_option() == ObPDMLOption::DISABLE) {
|
||||
// 如果显式 DISABLE_PARALLEL_DML 则不能开启 pdml
|
||||
is_use_pdml = false;
|
||||
} else if (global_hint.get_parallel_hint() == ObGlobalHint::UNSET_PARALLEL) {
|
||||
// 如果没有显式指定 PARALLEL(X) 则以 force_pdml_dop 为准,开启 pdml
|
||||
is_use_pdml = true;
|
||||
} else {
|
||||
// 如果显式指定了 PARALLEL(X) 则要求必须 parallel > 1 才开启 pdml,否则并行无效
|
||||
is_use_pdml = (global_hint.get_parallel_hint() > ObGlobalHint::DEFAULT_PARALLEL);
|
||||
}
|
||||
can_use_pdml = false;
|
||||
} 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()) {
|
||||
// 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) {
|
||||
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 {
|
||||
// case 2
|
||||
uint64_t query_dop = 1;
|
||||
const ObGlobalHint &global_hint = ctx_.get_query_ctx()->get_global_hint();
|
||||
if (OB_FAIL(session.get_force_parallel_query_dop(query_dop))) {
|
||||
LOG_WARN("fail get query dop", K(ret));
|
||||
} else if (global_hint.get_parallel_hint() > ObGlobalHint::DEFAULT_PARALLEL ||
|
||||
query_dop > ObGlobalHint::DEFAULT_PARALLEL || ctx_.is_online_ddl()) {
|
||||
// 当 px 开启,hint 中指定的 parallel > 1,或者 force parallel query > 1,并且有:
|
||||
// - HINT: /*+ ENABLE_PARALLEL_DML */
|
||||
// - 或 set _enable_parallel_dml = 1
|
||||
// 时开启 pdml
|
||||
if (global_hint.get_pdml_option() != ObPDMLOption::NOT_SPECIFIED) {
|
||||
is_use_pdml = (global_hint.get_pdml_option() == ObPDMLOption::ENABLE);
|
||||
} else {
|
||||
OZ (session.get_enable_parallel_dml(is_use_pdml));
|
||||
}
|
||||
}
|
||||
can_use_pdml = false;
|
||||
}
|
||||
// check pdml enable sql case
|
||||
if (OB_SUCC(ret) && is_use_pdml) {
|
||||
OZ(check_pdml_supported_feature(stmt, session, is_use_pdml));
|
||||
OZ(check_is_heap_table(stmt));
|
||||
|
||||
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));
|
||||
}
|
||||
LOG_DEBUG("check pdml enable", K(ret), K(is_use_pdml));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt,
|
||||
// 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();
|
||||
const ObDelUpdStmt &pdml_stmt = static_cast<const ObDelUpdStmt &>(stmt);
|
||||
ObSEArray<const ObDmlTableInfo*, 2> table_infos;
|
||||
bool enable_all_pdml_feature = false; // 默认非注入错误情况下,关闭PDML不稳定feature
|
||||
bool stmt_has_dblink = false;
|
||||
// 目前通过注入错误的方式来打开PDML不稳定功能,用于PDML全部功能的case回归
|
||||
// 对应的event注入任何类型的错误,都会打开PDML非稳定功能
|
||||
ret = OB_E(EventTable::EN_ENABLE_PDML_ALL_FEATURE) OB_SUCCESS;
|
||||
@ -503,15 +392,12 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt,
|
||||
} else if (table_infos.count() != 1) {
|
||||
is_use_pdml = false;
|
||||
ctx_.add_plan_note(PDML_DISABLED_BY_JOINED_TABLES);
|
||||
} else if (stmt::T_INSERT == stmt.get_stmt_type() &&
|
||||
static_cast< const ObInsertStmt &>(stmt).is_insert_up()) {
|
||||
} 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 (OB_FAIL(ObDblinkUtils::has_reverse_link_or_any_dblink(&stmt, stmt_has_dblink, true))) {
|
||||
LOG_WARN("failed to find dblink in stmt", K(ret));
|
||||
} else if (stmt_has_dblink) {
|
||||
} else if (ctx_.has_dblink()) {
|
||||
is_use_pdml = false;
|
||||
ctx_.set_has_dblink(true);
|
||||
} else if (!ctx_.has_trigger() && 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
|
||||
@ -526,7 +412,7 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt,
|
||||
// allow it use PDML plan
|
||||
is_use_pdml = false;
|
||||
ctx_.add_plan_note(PDML_DISABLED_BY_NESTED_SQL);
|
||||
} else if (stmt::T_DELETE == stmt.get_stmt_type()) {
|
||||
} 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;
|
||||
@ -549,7 +435,7 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt,
|
||||
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 == stmt.get_stmt_type()) {
|
||||
} 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);
|
||||
@ -558,7 +444,7 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt,
|
||||
ctx_.add_plan_note(PDML_DISABLED_BY_UPDATE_NOW);
|
||||
}
|
||||
}
|
||||
} else if (stmt::T_MERGE == stmt.get_stmt_type()) {
|
||||
} else if (stmt::T_MERGE == pdml_stmt.get_stmt_type()) {
|
||||
bool with_unique_global_idx = false;
|
||||
if (OB_FAIL(schema_guard->check_has_global_unique_index(
|
||||
session.get_effective_tenant_id(),
|
||||
@ -570,15 +456,6 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret) && !is_use_pdml && ctx_.is_online_ddl()) {
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
LOG_WARN("a online ddl expect PDML enabled. but it does not!", K(is_use_pdml), K(ret));
|
||||
LOG_USER_ERROR(OB_NOT_SUPPORTED, "online ddl without pdml");
|
||||
}
|
||||
if (OB_SUCC(ret) && ctx_.has_var_assign() && !ctx_.is_var_assign_only_in_root_stmt()) {
|
||||
is_use_pdml = false;
|
||||
}
|
||||
LOG_TRACE("check use all pdml feature", K(ret), K(is_use_pdml), K(ctx_.is_online_ddl()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -588,7 +465,7 @@ int ObOptimizer::check_is_heap_table(const ObDMLStmt &stmt)
|
||||
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 = static_cast<const ObDelUpdStmt &>(stmt);
|
||||
const ObDelUpdStmt *pdml_stmt = NULL;
|
||||
ObSEArray<const ObDmlTableInfo*, 1> dml_table_infos;
|
||||
// check if the target table is heap table
|
||||
if (OB_ISNULL(session)) {
|
||||
@ -596,7 +473,9 @@ int ObOptimizer::check_is_heap_table(const ObDMLStmt &stmt)
|
||||
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 (OB_FAIL(pdml_stmt.get_dml_table_infos(dml_table_infos))) {
|
||||
} 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;
|
||||
@ -616,150 +495,155 @@ int ObOptimizer::check_is_heap_table(const ObDMLStmt &stmt)
|
||||
int ObOptimizer::init_env_info(ObDMLStmt &stmt)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t parallel = 1;
|
||||
bool use_pdml = false;
|
||||
bool session_enable_parallel = false;
|
||||
bool has_var_assign = false;
|
||||
bool is_var_assign_only_in_root_stmt = false;
|
||||
bool stmt_has_dblink = false;
|
||||
uint64_t session_force_parallel_dop = 1;
|
||||
int64_t max_table_dop = 1;
|
||||
int64_t max_table_hint = 1;
|
||||
ObDMLStmt *target_stmt = &stmt;
|
||||
ObSQLSessionInfo *session = ctx_.get_session_info();
|
||||
bool force_serial_set_order = false;
|
||||
int64_t link_stmt_count = 0;
|
||||
if (OB_ISNULL(target_stmt) || OB_ISNULL(session)) {
|
||||
ObSQLSessionInfo *session_info = NULL;
|
||||
if (OB_ISNULL(session_info = ctx_.get_session_info())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else if (FALSE_IT(ctx_.set_is_online_ddl(session->get_ddl_info().is_ddl()))) {
|
||||
} else if (OB_FAIL(check_whether_contain_nested_sql(stmt))) {
|
||||
LOG_WARN("check whether contain nested sql failed", K(ret));
|
||||
} else if (OB_FAIL(get_stmt_parallel_info(target_stmt,
|
||||
max_table_dop,
|
||||
max_table_hint))) {
|
||||
LOG_WARN("failed to get attributes from stmt", K(ret));
|
||||
} else if (OB_FAIL(target_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_FALSE_IT(ctx_.set_has_var_assign(has_var_assign)) ||
|
||||
OB_FALSE_IT(ctx_.set_is_var_assign_only_in_root_stmt(is_var_assign_only_in_root_stmt))) {
|
||||
// do nothing
|
||||
} else if (OB_FAIL(check_pdml_enabled(*target_stmt, *session, use_pdml))) {
|
||||
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(init_parallel_policy(stmt, *session_info))) { // call after check pdml enabled
|
||||
LOG_WARN("fail to check enable pdml", K(ret));
|
||||
} else if (OB_FAIL(get_session_parallel_info(*target_stmt,
|
||||
use_pdml,
|
||||
session_enable_parallel,
|
||||
session_force_parallel_dop))) {
|
||||
LOG_WARN("failed to get session parallel info", 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");
|
||||
} else if (OB_FAIL(calc_link_stmt_count(*target_stmt, link_stmt_count))) {
|
||||
LOG_WARN("calc link stmt count failed", K(ret));
|
||||
} else {
|
||||
ctx_.set_serial_set_order(force_serial_set_order);
|
||||
ctx_.set_has_multiple_link_stmt(link_stmt_count > 1);
|
||||
parallel = ctx_.get_global_hint().get_parallel_hint();
|
||||
if (parallel <= 0) {
|
||||
parallel = ObGlobalHint::DEFAULT_PARALLEL;
|
||||
}
|
||||
ctx_.set_parallel(parallel);
|
||||
ctx_.set_use_pdml(use_pdml);
|
||||
if (ctx_.get_global_hint().get_parallel_hint() != ObGlobalHint::UNSET_PARALLEL) {
|
||||
ctx_.set_parallel_rule(PXParallelRule::MANUAL_HINT);
|
||||
ctx_.set_parallel(parallel);
|
||||
ctx_.add_plan_note(PARALLEL_ENABLED_BY_GLOBAL_HINT, parallel);
|
||||
} else if (max_table_hint > 1) {
|
||||
ctx_.set_parallel_rule(PXParallelRule::MANUAL_TABLE_HINT);
|
||||
ctx_.set_parallel(max_table_hint); // FIXME:nonsense, will use table hint in stmt level
|
||||
ctx_.add_plan_note(PARALLEL_ENABLED_BY_TABLE_HINT, max_table_hint);
|
||||
} else if (session_force_parallel_dop > 1) {
|
||||
ctx_.set_parallel_rule(PXParallelRule::SESSION_FORCE_PARALLEL);
|
||||
ctx_.set_parallel(session_force_parallel_dop);
|
||||
ctx_.add_plan_note(PARALLEL_ENABLED_BY_SESSION, session_force_parallel_dop);
|
||||
} else if (max_table_dop > 1 && session_enable_parallel) {
|
||||
ctx_.set_parallel_rule(PXParallelRule::MANUAL_TABLE_DOP);
|
||||
ctx_.set_parallel(max_table_dop);
|
||||
ctx_.add_plan_note(PARALLEL_ENABLED_BY_TABLE_PROPERTY, max_table_dop);
|
||||
} else {
|
||||
ctx_.set_parallel_rule(PXParallelRule::USE_PX_DEFAULT);
|
||||
ctx_.set_parallel(ObGlobalHint::DEFAULT_PARALLEL);
|
||||
}
|
||||
//following above rule, but if stmt contain pl_udf, force das, parallel should be 1
|
||||
if (ctx_.get_parallel() > 1 && ctx_.has_pl_udf()) {
|
||||
ctx_.set_parallel_rule(PXParallelRule::PL_UDF_DAS_FORCE_SERIALIZE);
|
||||
ctx_.set_parallel(1);
|
||||
ctx_.add_plan_note(PARALLEL_DISABLED_BY_PL_UDF_DAS, 1);
|
||||
}
|
||||
if (ctx_.has_dblink()) {
|
||||
//if stmt contain dblink, force das, parallel should be 1
|
||||
ctx_.set_parallel(1);
|
||||
ctx_.add_plan_note(PARALLEL_DISABLED_BY_DBLINK, 1);
|
||||
}
|
||||
bool is_direct_insert = false;
|
||||
if (OB_FAIL(ObTableDirectInsertService::check_direct_insert(ctx_, stmt, is_direct_insert))) {
|
||||
LOG_WARN("failed to check direct insert", KR(ret));
|
||||
} else if (is_direct_insert) {
|
||||
ctx_.add_plan_note(DIRECT_MODE_INSERT_INTO_SELECT);
|
||||
}
|
||||
}
|
||||
|
||||
// init column usage info
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(extract_column_usage_info(stmt))) {
|
||||
LOG_WARN("failed to extract column usage info", K(ret));
|
||||
}
|
||||
}
|
||||
|
||||
//init cost model
|
||||
uint64_t tenant_id = session->get_effective_tenant_id();
|
||||
omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id));
|
||||
bool rowsets_enabled = tenant_config.is_valid() && tenant_config->_rowsets_enabled;
|
||||
if (OB_FAIL(stmt.get_query_ctx()->get_global_hint().opt_params_.get_bool_opt_param(
|
||||
ObOptParamHint::ROWSETS_ENABLED, rowsets_enabled))) {
|
||||
LOG_WARN("fail to check rowsets enabled", K(ret));
|
||||
} else if (rowsets_enabled) {
|
||||
ctx_.set_cost_model_type(ObOptEstCost::VECTOR_MODEL);
|
||||
} else {
|
||||
ctx_.set_cost_model_type(ObOptEstCost::NORMAL_MODEL);
|
||||
}
|
||||
|
||||
// check if stmt has subquery in function table
|
||||
if (OB_SUCC(ret)){
|
||||
bool has_subquery_in_function_table = false;
|
||||
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 {
|
||||
ctx_.set_has_subquery_in_function_table(has_subquery_in_function_table);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_TRACE("succeed to init optimization env", K(ctx_.use_pdml()), K(ctx_.get_parallel()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObOptimizer::check_unique_index(const ObIArray<ObColumnRefRawExpr*> &column_exprs,
|
||||
bool &has_unique_index) const
|
||||
int ObOptimizer::extract_opt_ctx_basic_flags(const ObDMLStmt &stmt, ObSQLSessionInfo &session)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
for (int64_t j = 0; OB_SUCC(ret) && j < column_exprs.count(); ++j) {
|
||||
if (NULL == column_exprs.at(j)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid argument", K(ret));
|
||||
} else {
|
||||
ObRawExpr *target_expr = column_exprs.at(j);
|
||||
if (target_expr->is_column_ref_expr()) {
|
||||
ObColumnRefRawExpr *column_ref_expr = (ObColumnRefRawExpr*)(target_expr);
|
||||
if (column_ref_expr->is_virtual_generated_column() &&
|
||||
!OB_ISNULL(column_ref_expr->get_dependant_expr()) &&
|
||||
column_ref_expr->get_dependant_expr()->get_expr_type() == T_OP_SHADOW_UK_PROJECT) {
|
||||
has_unique_index = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
int64_t link_stmt_count = 0;
|
||||
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
|
||||
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(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(ctx_.get_global_hint().opt_params_.get_bool_opt_param(ObOptParamHint::ROWSETS_ENABLED, rowsets_enabled))) {
|
||||
LOG_WARN("fail to check rowsets enabled", K(ret));
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
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 (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_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 (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_.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_parallel_degree_limit()), K(ctx_.get_parallel_min_scan_time_threshold()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObOptimizer::set_auto_dop_params(const ObSQLSessionInfo &session)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const uint64_t default_parallel_degree_limit = 256;
|
||||
uint64_t parallel_degree_limit = default_parallel_degree_limit;
|
||||
uint64_t parallel_min_scan_time_threshold = 1000;
|
||||
int64_t parallel_servers_target = 0;
|
||||
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));
|
||||
} else if (0 != parallel_degree_limit) {
|
||||
/* do nothing */
|
||||
} else if (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 if (parallel_servers_target > 0) {
|
||||
parallel_degree_limit = parallel_servers_target;
|
||||
} else {
|
||||
parallel_degree_limit = default_parallel_degree_limit;
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
ctx_.set_parallel_degree_limit(parallel_degree_limit);
|
||||
ctx_.set_parallel_min_scan_time_threshold(parallel_min_scan_time_threshold);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user