Files
oceanbase/src/sql/optimizer/ob_log_optimizer_stats_gathering.cpp
2024-02-07 11:01:37 +00:00

196 lines
7.1 KiB
C++

/**
* Copyright (c) 2023 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 "sql/optimizer/ob_log_optimizer_stats_gathering.h"
#include "sql/optimizer/ob_optimizer_util.h"
#include "sql/rewrite/ob_transform_utils.h"
#include "pl/sys_package/ob_dbms_stats.h"
#include "sql/optimizer/ob_log_plan.h"
#include "sql/optimizer/ob_optimizer_context.h"
#include "ob_opt_est_cost.h"
#include "share/schema/ob_table_schema.h"
#include "share/schema/ob_schema_struct.h"
using namespace oceanbase;
using namespace sql;
using namespace oceanbase::common;
namespace oceanbase
{
namespace sql
{
const char *ObLogOptimizerStatsGathering::get_name() const
{
static const char *stats_gathering_name_[2] =
{
"OPTIMIZER STATS MERGE",
"OPTIMIZER STATS GATHER",
};
return stats_gathering_name_[osg_type_ == OSG_TYPE::MERGE_OSG ? 0 : 1];
}
int ObLogOptimizerStatsGathering::get_op_exprs(ObIArray<ObRawExpr*> &all_exprs)
{
int ret = OB_SUCCESS;
if (NULL != calc_part_id_expr_ && OB_FAIL(all_exprs.push_back(calc_part_id_expr_))) {
LOG_WARN("failed to push back expr", K(ret));
} else if (OB_FAIL(append(all_exprs, get_col_conv_exprs()))) {
LOG_WARN("fail to append column conv expr", K(ret));
} else if (OB_FAIL(append(all_exprs, get_generated_column_exprs()))) {
LOG_WARN("fail to append column conv expr", K(ret));
} else if (OB_FAIL(ObLogicalOperator::get_op_exprs(all_exprs))) {
LOG_WARN("failed to get exprs", K(ret));
} else { /*do nothing*/ }
return ret;
}
// use this function to calc the part num, instead of the class member(part_num_);
int ObLogOptimizerStatsGathering::inner_get_table_schema(const ObTableSchema *&table_schema) {
int ret = OB_SUCCESS;
ObSqlSchemaGuard *schema_guard = NULL;
ObOptimizerContext *opt_ctx = NULL;
const ObDMLStmt *stmt = NULL;
if (OB_ISNULL(get_plan())
|| OB_ISNULL(opt_ctx = &get_plan()->get_optimizer_context())
|| OB_ISNULL(schema_guard = opt_ctx->get_sql_schema_guard())
|| OB_ISNULL(stmt = get_plan()->get_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_UNLIKELY(!stmt->is_insert_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected stmt", K(ret), KPC(stmt));
} else {
const ObInsertStmt *ins_stmt = static_cast<const ObInsertStmt*>(stmt);
uint64_t table_id = ins_stmt->get_insert_table_info().table_id_;
uint64_t ref_table_id = ins_stmt->get_insert_table_info().ref_table_id_;
if (OB_FAIL(schema_guard->get_table_schema(table_id, ref_table_id, ins_stmt, table_schema))) {
LOG_WARN("fail to get table schema", K(ref_table_id), K(table_schema), K(ret));
} else if (OB_ISNULL(table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index schema should not be null", K(table_schema), K(ret));
}
}
return ret;
}
int ObLogOptimizerStatsGathering::est_cost()
{
int ret = OB_SUCCESS;
ObLogicalOperator *child = NULL;
int64_t parallel = get_parallel();
uint64_t total_part_num = 0;
const ObTableSchema *tab_schema = NULL;
if (OB_ISNULL(child = get_child(first_child))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(child), K(ret));
} else if (OB_FAIL(inner_get_table_schema(tab_schema))) {
LOG_WARN("fail to get table schema", K(ret));
} else if (OB_FAIL(inner_get_stat_part_cnt(tab_schema, total_part_num))) {
LOG_WARN("fail to get pstat num", K(ret));
} else if (OB_UNLIKELY(parallel < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected parallel", K(parallel), K(ret));
} else {
ObOptimizerContext &opt_ctx = get_plan()->get_optimizer_context();
op_cost_ = 0;
if (osg_type_ != OSG_TYPE::GATHER_OSG) {
//for normal_osg and merge_osg calc the inner_sql_cost;
uint64_t stats_size = ((get_col_conv_exprs().count() + get_generated_column_exprs().count() + 1)
* (total_part_num));
double sql_num = stats_size / 2000; //2000 is the max_num of wirte stats in ObDbmsStatsUtils::split_batch_write
op_cost_ += sql_num * 12800;
}
if (osg_type_ != OSG_TYPE::MERGE_OSG) {
//for normal_osg and merge_osg calc the calc_stats cost;
//TODO: use a more accurate model.
op_cost_ += ObOptEstCost::cost_get_rows(child->get_card() / parallel, opt_ctx);
}
set_cost(op_cost_ + child->get_cost());
set_card(child->get_card());
set_width(child->get_width());
}
return ret;
}
int ObLogOptimizerStatsGathering::get_target_osg_id(uint64_t &target_id)
{
int ret = OB_SUCCESS;
target_id = OB_INVALID_ID;
ObLogicalOperator *node = get_parent();
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else {
bool is_find = false;
while (NULL != node && !is_find) {
if (!node->is_osg_operator() || !static_cast<ObLogOptimizerStatsGathering *>(node)->is_merge_osg()) {
node = node->get_parent();
} else {
is_find = true;
target_id = node->get_op_id();
}
}
if (OB_SUCC(ret) && !is_find) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("can not find next producer id", K(ret));
}
}
return ret;
}
int ObLogOptimizerStatsGathering::inner_replace_op_exprs(ObRawExprReplacer &replacer)
{
int ret = OB_SUCCESS;
if (OB_FAIL(replace_exprs_action(replacer, col_conv_exprs_))) {
LOG_WARN("failed to replace exprs", K(ret));
} else if (OB_FAIL(replace_exprs_action(replacer, generated_column_exprs_))) {
LOG_WARN("failed to replace exprs", K(ret));
}
return ret;
}
// calc stats cnt base on part_type and part_cnt;
int ObLogOptimizerStatsGathering::inner_get_stat_part_cnt(const ObTableSchema *table_schema, uint64_t &part_num)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table schema is null", K(ret));
} else if (!table_schema->is_partitioned_table()) {
part_num = 1; //for non-part table, only have global stats.
} else {
part_num = 0;
if (share::schema::PARTITION_LEVEL_ONE == table_schema->get_part_level()) {
part_num += table_schema->get_part_option().get_part_num() + 1;
} else if (share::schema::PARTITION_LEVEL_TWO == table_schema->get_part_level()) {
part_num = table_schema->get_part_option().get_part_num();
int total_subpart_num = 0;
ObPartition *cur_part = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < part_num; ++i) {
if (OB_ISNULL(cur_part = (table_schema->get_part_array())[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else {
total_subpart_num += cur_part->get_sub_part_num();
}
}
if (OB_SUCC(ret)) {
part_num += total_subpart_num + 1;
}
}
}
return ret;
}
}
}