905 lines
34 KiB
C++
905 lines
34 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 "ob_log_group_by.h"
|
|
#include "lib/allocator/page_arena.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_replacer.h"
|
|
#include "ob_log_operator_factory.h"
|
|
#include "ob_log_exchange.h"
|
|
#include "ob_log_sort.h"
|
|
#include "ob_log_topk.h"
|
|
#include "ob_log_material.h"
|
|
#include "ob_log_table_scan.h"
|
|
#include "ob_optimizer_context.h"
|
|
#include "ob_optimizer_util.h"
|
|
#include "ob_opt_est_cost.h"
|
|
#include "ob_select_log_plan.h"
|
|
#include "common/ob_smart_call.h"
|
|
#include "ob_opt_selectivity.h"
|
|
#include "ob_log_operator_factory.h"
|
|
#include "sql/optimizer/ob_join_order.h"
|
|
#include "sql/rewrite/ob_transform_utils.h"
|
|
|
|
using namespace oceanbase;
|
|
using namespace sql;
|
|
using namespace oceanbase::common;
|
|
|
|
int ObThreeStageAggrInfo::assign(const ObThreeStageAggrInfo &info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
aggr_stage_ = info.aggr_stage_;
|
|
distinct_aggr_count_ = info.distinct_aggr_count_;
|
|
aggr_code_idx_ = info.aggr_code_idx_;
|
|
aggr_code_expr_ = info.aggr_code_expr_;
|
|
aggr_code_ndv_ = info.aggr_code_ndv_;
|
|
if (OB_FAIL(distinct_exprs_.assign(info.distinct_exprs_))) {
|
|
LOG_WARN("failed to assign distinct exprs", K(ret));
|
|
} else if (OB_FAIL(distinct_aggr_batch_.assign(info.distinct_aggr_batch_))) {
|
|
LOG_WARN("failed to assign distinct col idx", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObRollupAdaptiveInfo::assign(const ObRollupAdaptiveInfo &info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
rollup_id_expr_ = info.rollup_id_expr_;
|
|
rollup_status_ = info.rollup_status_;
|
|
enable_encode_sort_ = info.enable_encode_sort_;
|
|
sort_keys_.reset();
|
|
ecd_sort_keys_.reset();
|
|
if (OB_FAIL(append(sort_keys_, info.sort_keys_))) {
|
|
LOG_WARN("failed to assign distinct col idx", K(ret));
|
|
} else if (OB_FAIL(append(ecd_sort_keys_, info.ecd_sort_keys_))) {
|
|
LOG_WARN("failed to append sort keys", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::get_explain_name_internal(char *buf,
|
|
const int64_t buf_len,
|
|
int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (SCALAR_AGGREGATE == algo_) {
|
|
ret = BUF_PRINTF("SCALAR ");
|
|
} else if (HASH_AGGREGATE == algo_) {
|
|
ret = BUF_PRINTF("HASH ");
|
|
} else {
|
|
if (ObRollupStatus::ROLLUP_DISTRIBUTOR != rollup_adaptive_info_.rollup_status_) {
|
|
ret = BUF_PRINTF("MERGE ");
|
|
} else {
|
|
// inner sort in groupby
|
|
ret = BUF_PRINTF("SORT ");
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ret = BUF_PRINTF("%s", get_name());
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (ObRollupStatus::ROLLUP_DISTRIBUTOR == rollup_adaptive_info_.rollup_status_) {
|
|
ret = BUF_PRINTF(" ROLLUP DISTRIBUTOR");
|
|
} else if (ObRollupStatus::ROLLUP_COLLECTOR == rollup_adaptive_info_.rollup_status_) {
|
|
ret = BUF_PRINTF(" ROLLUP COLLECTOR");
|
|
}
|
|
|
|
if (OB_SUCC(ret) && from_pivot_) {
|
|
ret = BUF_PRINTF(" PIVOT");
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("BUF_PRINTF fails", K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::set_group_by_exprs(const common::ObIArray<ObRawExpr *> &group_by_exprs)
|
|
{
|
|
return group_exprs_.assign(group_by_exprs);
|
|
}
|
|
|
|
int ObLogGroupBy::set_rollup_exprs(const common::ObIArray<ObRawExpr *> &rollup_exprs)
|
|
{
|
|
return rollup_exprs_.assign(rollup_exprs);
|
|
}
|
|
|
|
int ObLogGroupBy::set_aggr_exprs(const common::ObIArray<ObAggFunRawExpr *> &aggr_exprs)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < aggr_exprs.count(); i++) {
|
|
ObAggFunRawExpr *aggr_expr = aggr_exprs.at(i);
|
|
if (OB_ISNULL(aggr_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("aggr_expr is null", K(ret));
|
|
} else {
|
|
ret = aggr_exprs_.push_back(aggr_expr);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::get_group_rollup_exprs(common::ObIArray<ObRawExpr *> &group_rollup_exprs) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(append(group_rollup_exprs, group_exprs_))) {
|
|
LOG_WARN("failed to append group exprs into group rollup exprs.", K(ret));
|
|
} else if (OB_FAIL(append(group_rollup_exprs, rollup_exprs_))) {
|
|
LOG_WARN("failed to append rollup exprs into group rollup exprs.", K(ret));
|
|
} else { /*do nothing*/ }
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::get_op_exprs(ObIArray<ObRawExpr*> &all_exprs)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(append(all_exprs, group_exprs_))) {
|
|
LOG_WARN("failed to add exprs to ctx", K(ret));
|
|
} else if (OB_FAIL(append_array_no_dup(all_exprs, rollup_exprs_))) {
|
|
LOG_WARN("failed to add exprs to ctx", K(ret));
|
|
} else if (OB_FAIL(append(all_exprs, aggr_exprs_))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else if (is_three_stage_aggr() && all_exprs.push_back(three_stage_info_.aggr_code_expr_)) {
|
|
LOG_WARN("failed to push back exprs", K(ret));
|
|
} else if (NULL != rollup_adaptive_info_.rollup_id_expr_ &&
|
|
OB_FAIL(all_exprs.push_back(rollup_adaptive_info_.rollup_id_expr_))) {
|
|
LOG_WARN("failed to add rollup id expr", K(ret));
|
|
} else if (OB_FAIL(ObLogicalOperator::get_op_exprs(all_exprs))) {
|
|
LOG_WARN("failed to get op exprs", K(ret));
|
|
} else { /*do nothing*/ }
|
|
|
|
if (OB_SUCC(ret) && is_first_stage()) {
|
|
for (int64_t i = 0; i < three_stage_info_.distinct_aggr_batch_.count() && OB_SUCC(ret); ++i) {
|
|
const ObDistinctAggrBatch &distinct_batch = three_stage_info_.distinct_aggr_batch_.at(i);
|
|
for (int64_t j = 0; j < distinct_batch.mocked_params_.count() && OB_SUCC(ret); ++j) {
|
|
if (OB_FAIL(all_exprs.push_back(distinct_batch.mocked_params_.at(j).first))) {
|
|
LOG_WARN("failed to push back distinct expr", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && rollup_adaptive_info_.enable_encode_sort_) {
|
|
for (int64_t i = 0; i < rollup_adaptive_info_.sort_keys_.count() && OB_SUCC(ret); ++i) {
|
|
if (OB_FAIL(all_exprs.push_back(rollup_adaptive_info_.sort_keys_.at(i).expr_))) {
|
|
LOG_WARN("failed to push back distinct expr", K(ret));
|
|
}
|
|
}
|
|
for (int64_t i = 0; i < rollup_adaptive_info_.ecd_sort_keys_.count() && OB_SUCC(ret); ++i) {
|
|
if (OB_FAIL(all_exprs.push_back(rollup_adaptive_info_.ecd_sort_keys_.at(i).expr_))) {
|
|
LOG_WARN("failed to push back distinct expr", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
uint64_t ObLogGroupBy::hash(uint64_t seed) const
|
|
{
|
|
uint64_t hash_value = seed;
|
|
hash_value = do_hash(algo_, hash_value);
|
|
hash_value = ObLogicalOperator::hash(hash_value);
|
|
|
|
return hash_value;
|
|
}
|
|
|
|
int ObLogGroupBy::get_plan_item_info(PlanText &plan_text,
|
|
ObSqlPlanItem &plan_item)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(ObLogicalOperator::get_plan_item_info(plan_text, plan_item))) {
|
|
LOG_WARN("failed to get plan item info", K(ret));
|
|
} else {
|
|
BEGIN_BUF_PRINT;
|
|
if (OB_FAIL(get_explain_name_internal(buf, buf_len, pos))) {
|
|
LOG_WARN("failed to get explain name", K(ret));
|
|
}
|
|
END_BUF_PRINT(plan_item.operation_, plan_item.operation_len_);
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
BEGIN_BUF_PRINT;
|
|
const ObIArray<ObRawExpr *> &group = get_group_by_exprs();
|
|
EXPLAIN_PRINT_EXPRS(group, type);
|
|
const ObIArray<ObRawExpr *> &rollup = get_rollup_exprs();
|
|
if (OB_FAIL(ret) || (rollup.count() <= 0)) {
|
|
} else if(OB_FAIL(BUF_PRINTF(", "))) {
|
|
LOG_WARN("BUF_PRINTF fails", K(ret));
|
|
} else {
|
|
EXPLAIN_PRINT_EXPRS(rollup, type);
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(BUF_PRINTF(", "))) {
|
|
LOG_WARN("BUF_PRINTF fails", K(ret));
|
|
} else {
|
|
const ObIArray<ObRawExpr *> &agg_func = get_aggr_funcs();
|
|
EXPLAIN_PRINT_EXPRS(agg_func, type);
|
|
}
|
|
END_BUF_PRINT(plan_item.special_predicates_,
|
|
plan_item.special_predicates_len_);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::est_cost()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
double child_card = 0.0;
|
|
double child_ndv = 0.0;
|
|
double selectivity = 1.0;
|
|
double group_cost = 0.0;
|
|
ObLogicalOperator *child = get_child(ObLogicalOperator::first_child);
|
|
if (OB_ISNULL(child)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(child));
|
|
} else if (OB_FAIL(get_child_est_info(get_parallel(), child_card, child_ndv, selectivity))) {
|
|
LOG_WARN("failed to get chidl est info", K(ret));
|
|
} else if (OB_FAIL(inner_est_cost(get_parallel(),
|
|
child_card,
|
|
child_ndv,
|
|
distinct_per_dop_,
|
|
group_cost))) {
|
|
LOG_WARN("failed to est group by cost", K(ret));
|
|
} else {
|
|
distinct_card_ = child_ndv;
|
|
set_card(distinct_card_ * selectivity);
|
|
set_cost(child->get_cost() + group_cost);
|
|
set_op_cost(group_cost);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::do_re_est_cost(EstimateCostInfo ¶m, double &card, double &op_cost, double &cost)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
double child_card = 0.0;
|
|
double child_ndv = 0.0;
|
|
double selectivity = 1.0;
|
|
ObLogicalOperator *child = get_child(ObLogicalOperator::first_child);
|
|
const int64_t parallel = param.need_parallel_;
|
|
double number_of_copies = get_number_of_copies();
|
|
if (OB_ISNULL(child) || OB_UNLIKELY(number_of_copies < 1)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(child), K(number_of_copies));
|
|
} else if (OB_FAIL(get_child_est_info(parallel, child_card, child_ndv, selectivity))) {
|
|
LOG_WARN("failed to get chidl est info", K(ret));
|
|
} else {
|
|
double child_cost = child->get_cost();
|
|
double need_ndv = child_ndv;
|
|
double origin_child_card = child_card;
|
|
bool need_scale_ndv = false;
|
|
if (param.need_row_count_ >= 0 &&
|
|
child->get_card() > 0 &&
|
|
child_ndv > 0 &&
|
|
param.need_row_count_ < child_ndv) {
|
|
need_ndv = param.need_row_count_;
|
|
if (selectivity > OB_DOUBLE_EPSINON) {
|
|
need_ndv /= selectivity;
|
|
}
|
|
if (child_card > 0) {
|
|
param.need_row_count_ = child_card * (1 - std::pow((1 - need_ndv / child_ndv), child_ndv / child_card));
|
|
param.need_row_count_ /= number_of_copies;
|
|
} else {
|
|
param.need_row_count_ = 0;
|
|
}
|
|
} else {
|
|
param.need_row_count_ = -1;
|
|
need_scale_ndv = true;
|
|
}
|
|
if (is_block_op()) {
|
|
param.need_row_count_ = -1; //reset need row count
|
|
}
|
|
if (OB_FAIL(SMART_CALL(child->re_est_cost(param, child_card, child_cost)))) {
|
|
LOG_WARN("failed to re est child cost", K(ret));
|
|
} else {
|
|
// At the first stage, child output will be replicated
|
|
child_card = child_card * number_of_copies;
|
|
if (need_scale_ndv) {
|
|
need_ndv = std::min(child_ndv, ObOptSelectivity::scale_distinct(child_card, origin_child_card, child_ndv));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(inner_est_cost(parallel,
|
|
child_card,
|
|
need_ndv,
|
|
distinct_per_dop_,
|
|
op_cost))) {
|
|
LOG_WARN("failed to est distinct cost", K(ret));
|
|
} else {
|
|
cost = child_cost + op_cost;
|
|
card = need_ndv * selectivity;
|
|
if (param.override_) {
|
|
set_total_ndv(need_ndv);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::inner_est_cost(const int64_t parallel, double child_card, double &child_ndv, double &per_dop_ndv, double &op_cost)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
double per_dop_card = 0.0;
|
|
per_dop_ndv = 0.0;
|
|
common::ObSEArray<ObRawExpr *, 8> group_rollup_exprs;
|
|
ObLogicalOperator *child = get_child(ObLogicalOperator::first_child);
|
|
if (OB_ISNULL(get_plan()) ||
|
|
OB_ISNULL(child)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(child));
|
|
} else if (OB_UNLIKELY(parallel < 1)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(child));
|
|
} else if (OB_FAIL(get_group_rollup_exprs(group_rollup_exprs))) {
|
|
LOG_WARN("failed to get group rollup exprs", K(ret));
|
|
} else {
|
|
per_dop_card = child_card / parallel;
|
|
if ((get_group_by_exprs().empty() && get_rollup_exprs().empty()) || SCALAR_AGGREGATE == algo_) {
|
|
per_dop_ndv = 1.0;
|
|
} else if (parallel > 1) {
|
|
if (is_push_down()) {
|
|
per_dop_ndv = ObOptSelectivity::scale_distinct(per_dop_card, child_card, child_ndv);
|
|
} else {
|
|
per_dop_ndv = child_ndv / parallel;
|
|
}
|
|
} else {
|
|
per_dop_ndv = child_ndv;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ObOptimizerContext &opt_ctx = get_plan()->get_optimizer_context();
|
|
if (SCALAR_AGGREGATE == algo_) {
|
|
op_cost = ObOptEstCost::cost_scalar_group(per_dop_card,
|
|
get_aggr_funcs().count(),
|
|
opt_ctx);
|
|
} else if (MERGE_AGGREGATE == algo_) {
|
|
op_cost = ObOptEstCost::cost_merge_group(per_dop_card,
|
|
per_dop_ndv,
|
|
child->get_width(),
|
|
group_rollup_exprs,
|
|
get_aggr_funcs().count(),
|
|
opt_ctx);
|
|
} else {
|
|
op_cost = ObOptEstCost::cost_hash_group(per_dop_card,
|
|
per_dop_ndv,
|
|
child->get_width(),
|
|
group_exprs_,
|
|
get_aggr_funcs().count(),
|
|
opt_ctx);
|
|
}
|
|
|
|
child_ndv = std::min(child_card, per_dop_ndv * parallel);
|
|
if (SCALAR_AGGREGATE == algo_) {
|
|
child_ndv = std::max(1.0, child_ndv);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::get_child_est_info(const int64_t parallel, double &child_card, double &child_ndv, double &selectivity)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObLogicalOperator *child = get_child(ObLogicalOperator::first_child);
|
|
if (OB_ISNULL(child) || OB_ISNULL(get_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(child));
|
|
} else if (OB_UNLIKELY(parallel < 1)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(child));
|
|
} else if ((get_group_by_exprs().empty() && get_rollup_exprs().empty())
|
|
|| SCALAR_AGGREGATE == algo_) {
|
|
child_card = child->get_card();
|
|
child_ndv = parallel;
|
|
} else {
|
|
child_card = child->get_card();
|
|
child_ndv = get_total_ndv();
|
|
}
|
|
//having filter selectivity
|
|
if (OB_SUCC(ret)) {
|
|
// At the first stage, child output will be replicated
|
|
child_card = child_card * get_number_of_copies();
|
|
get_plan()->get_selectivity_ctx().init_row_count(get_origin_child_card(), child_ndv);
|
|
if (OB_FAIL(ObOptSelectivity::calculate_selectivity(get_plan()->get_update_table_metas(),
|
|
get_plan()->get_selectivity_ctx(),
|
|
get_filter_exprs(),
|
|
selectivity,
|
|
get_plan()->get_predicate_selectivities()))) {
|
|
LOG_WARN("failed to calculate selectivity", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::est_width()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
double width = 0.0;
|
|
ObSEArray<ObRawExpr*, 16> output_exprs;
|
|
if (OB_ISNULL(get_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid plan", K(ret));
|
|
} else if (OB_FAIL(get_gby_output_exprs(output_exprs))) {
|
|
LOG_WARN("failed to compute gby output column exprs", K(ret));
|
|
} else if (OB_FAIL(ObOptEstCost::estimate_width_for_exprs(get_plan()->get_basic_table_metas(),
|
|
get_plan()->get_selectivity_ctx(),
|
|
output_exprs,
|
|
width))) {
|
|
LOG_WARN("failed to estimate width for output gby column exprs", K(ret));
|
|
} else {
|
|
set_width(width);
|
|
LOG_TRACE("est width for gby", K(output_exprs), K(width));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::get_gby_output_exprs(ObIArray<ObRawExpr *> &output_exprs)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObLogPlan *plan = NULL;
|
|
ObSEArray<ObRawExpr*, 16> candi_exprs;
|
|
ObSEArray<ObRawExpr*, 16> extracted_col_or_aggr_exprs;
|
|
if (OB_ISNULL(plan = get_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid input", K(ret));
|
|
} else if (OB_FAIL(append_array_no_dup(candi_exprs, plan->get_winfunc_exprs_for_width_est()))) {
|
|
LOG_WARN("failed to add into output exprs", K(ret));
|
|
} else if (OB_FAIL(append_array_no_dup(candi_exprs, plan->get_select_item_exprs_for_width_est()))) {
|
|
LOG_WARN("failed to add into output exprs", K(ret));
|
|
} else if (OB_FAIL(append_array_no_dup(candi_exprs, plan->get_orderby_exprs_for_width_est()))) {
|
|
LOG_WARN("failed to add into output exprs", K(ret));
|
|
} else if (OB_FAIL(ObRawExprUtils::extract_col_aggr_exprs(candi_exprs,
|
|
extracted_col_or_aggr_exprs))) {
|
|
LOG_WARN("failed to extract exprs", K(ret));
|
|
} else if (OB_FAIL(append_array_no_dup(output_exprs, extracted_col_or_aggr_exprs))) {
|
|
LOG_WARN("failed to add into output exprs", K(ret));
|
|
} else {/*do nothing*/}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::inner_replace_op_exprs(ObRawExprReplacer &replacer)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(replace_exprs_action(replacer, get_group_by_exprs()))) {
|
|
LOG_WARN("failed to extract subplan params in log group by exprs", K(ret));
|
|
} else if (OB_FAIL(replace_exprs_action(replacer, get_rollup_exprs()))) {
|
|
LOG_WARN("failed to extract subplan params in log rollup exprs", K(ret));
|
|
} else if (OB_FAIL(replace_exprs_action(replacer, get_aggr_funcs()))) {
|
|
LOG_WARN("failed to extract subplan params in log agg funcs", K(ret));
|
|
} else {
|
|
for(int64_t i = 0; OB_SUCC(ret) && i < rollup_adaptive_info_.sort_keys_.count(); ++i) {
|
|
OrderItem &cur_order_item = rollup_adaptive_info_.sort_keys_.at(i);
|
|
if (OB_FAIL(replace_expr_action(replacer, cur_order_item.expr_))) {
|
|
LOG_WARN("failed to resolve ref params in sort key ", K(cur_order_item), K(ret));
|
|
} else { /* Do nothing */ }
|
|
}
|
|
for(int64_t i = 0; OB_SUCC(ret) && i < rollup_adaptive_info_.ecd_sort_keys_.count(); ++i) {
|
|
OrderItem &cur_order_item = rollup_adaptive_info_.ecd_sort_keys_.at(i);
|
|
if (OB_FAIL(replace_expr_action(replacer, cur_order_item.expr_))) {
|
|
LOG_WARN("failed to resolve ref params in sort key ", K(cur_order_item), K(ret));
|
|
} else { /* Do nothing */ }
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && is_three_stage_aggr()) {
|
|
if (OB_FAIL(replace_exprs_action(replacer, three_stage_info_.distinct_exprs_))) {
|
|
LOG_WARN("failed to replace three stage info distinct exprs", K(ret));
|
|
} else {
|
|
for(int64_t i = 0; OB_SUCC(ret) && i < three_stage_info_.distinct_aggr_batch_.count(); ++i) {
|
|
ObDistinctAggrBatch &distinct_batch = three_stage_info_.distinct_aggr_batch_.at(i);
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < distinct_batch.mocked_params_.count(); ++j) {
|
|
if (OB_FAIL(replace_expr_action(replacer, distinct_batch.mocked_params_.at(j).first))) {
|
|
LOG_WARN("failed to replace distinct expr", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::print_outline_data(PlanText &plan_text)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObDMLStmt *stmt = NULL;
|
|
ObString qb_name;
|
|
if (is_push_down()) {
|
|
/* print outline in top group by */
|
|
} else if (OB_ISNULL(get_plan()) || OB_ISNULL(stmt = get_plan()->get_stmt())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected NULL", K(ret), K(get_plan()), K(stmt));
|
|
} else if (OB_FAIL(stmt->get_qb_name(qb_name))) {
|
|
LOG_WARN("fail to get qb_name", K(ret), K(stmt->get_stmt_id()));
|
|
} else {
|
|
if (OB_SUCC(ret) && has_push_down_) {
|
|
ObOptHint hint(T_GBY_PUSHDOWN);
|
|
hint.set_qb_name(qb_name);
|
|
if (OB_FAIL(hint.print_hint(plan_text))) {
|
|
LOG_WARN("failed to print hint", K(ret), K(hint));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && (use_hash_aggr_ || use_part_sort_)) {
|
|
ObAggHint hint(use_hash_aggr_ ? T_USE_HASH_AGGREGATE : T_NO_USE_HASH_AGGREGATE);
|
|
hint.set_qb_name(qb_name);
|
|
hint.set_use_partition_sort(use_part_sort_);
|
|
if (OB_FAIL(hint.print_hint(plan_text))) {
|
|
LOG_WARN("failed to print hint", K(ret), K(hint));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::print_used_hint(PlanText &plan_text)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObHint *hint = NULL;
|
|
if (is_push_down()) {
|
|
/* print outline in top group by */
|
|
} else if (OB_ISNULL(get_plan())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected NULL", K(ret), K(get_plan()));
|
|
} else if (NULL != (hint = get_plan()->get_log_plan_hint().get_normal_hint(T_GBY_PUSHDOWN))
|
|
&& hint->is_enable_hint() == has_push_down_
|
|
&& OB_FAIL(hint->print_hint(plan_text))) {
|
|
LOG_WARN("failed to print used hint for group by", K(ret), K(*hint));
|
|
} else if (NULL != (hint = get_plan()->get_log_plan_hint().get_normal_hint(T_USE_HASH_AGGREGATE))
|
|
&& hint->is_enable_hint() == use_hash_aggr_
|
|
&& static_cast<const ObAggHint*>(hint)->force_partition_sort() == use_part_sort_
|
|
&& OB_FAIL(hint->print_hint(plan_text))) {
|
|
LOG_WARN("failed to print used hint for group by", K(ret), K(*hint));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::compute_const_exprs()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObLogicalOperator *child = NULL;
|
|
if (OB_ISNULL(my_plan_) || OB_UNLIKELY(get_num_of_child() < 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("operator is invalid", K(ret), K(get_num_of_child()), K(my_plan_));
|
|
} else if (OB_ISNULL(child = get_child(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("child is null", K(ret), K(child));
|
|
} else if (!has_rollup() &&
|
|
OB_FAIL(append(get_output_const_exprs(), child->get_output_const_exprs()))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(get_filter_exprs(), get_output_const_exprs()))) {
|
|
LOG_WARN("failed to compute const conditionexprs", K(ret));
|
|
} else {/*do nothing*/}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::compute_equal_set()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
EqualSets *ordering_esets = NULL;
|
|
if (OB_ISNULL(my_plan_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("operator is invalid", K(ret), K(my_plan_));
|
|
} else if (!has_rollup()) {
|
|
if (OB_FAIL(ObLogicalOperator::compute_equal_set())) {
|
|
LOG_WARN("failed to compute equal set", K(ret));
|
|
}
|
|
} else if (filter_exprs_.empty()) {
|
|
set_output_equal_sets(&empty_expr_sets_);
|
|
} else if (OB_ISNULL(ordering_esets = get_plan()->create_equal_sets())) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to create equal sets", K(ret));
|
|
} else if (OB_FAIL(ObEqualAnalysis::compute_equal_set(
|
|
&my_plan_->get_allocator(),
|
|
filter_exprs_,
|
|
*ordering_esets))) {
|
|
LOG_WARN("failed to compute ordering output equal set", K(ret));
|
|
} else {
|
|
set_output_equal_sets(ordering_esets);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::compute_fd_item_set()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObLogicalOperator *child = NULL;
|
|
ObFdItemSet *fd_item_set = NULL;
|
|
ObTableFdItem *fd_item = NULL;
|
|
if (OB_ISNULL(child = get_child(ObLogicalOperator::first_child)) || OB_ISNULL(my_plan_) ||
|
|
OB_ISNULL(get_stmt())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpect null", K(ret), K(child), K(my_plan_), K(get_stmt()));
|
|
} else if (has_rollup()) {
|
|
// do nothing
|
|
} else if (OB_FAIL(my_plan_->get_fd_item_factory().create_fd_item_set(fd_item_set))) {
|
|
LOG_WARN("failed to create fd item set", K(ret));
|
|
} else if (OB_FAIL(fd_item_set->assign(child->get_fd_item_set()))) {
|
|
LOG_WARN("failed to assign fd item set", K(ret));
|
|
} else if (group_exprs_.empty()) {
|
|
// scalar group by
|
|
if (get_stmt()->is_select_stmt() && OB_FAIL(create_fd_item_from_select_list(fd_item_set))) {
|
|
LOG_WARN("failed to create fd item from select list", K(ret));
|
|
}
|
|
} else if (!ObTransformUtils::need_compute_fd_item_set(group_exprs_)) {
|
|
//do nothing
|
|
} else if (OB_FAIL(my_plan_->get_fd_item_factory().create_table_fd_item(
|
|
fd_item,
|
|
true,
|
|
group_exprs_,
|
|
get_table_set()))) {
|
|
LOG_WARN("failed to create fd item", K(ret));
|
|
} else if (OB_FAIL(fd_item_set->push_back(fd_item))) {
|
|
LOG_WARN("failed to push back fd item", K(ret));
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
/*do nothing*/
|
|
} else if (OB_NOT_NULL(fd_item_set) && // rollup 时 fd_item_set is null
|
|
OB_FAIL(deduce_const_exprs_and_ft_item_set(*fd_item_set))) {
|
|
LOG_WARN("falied to deduce fd item set", K(ret));
|
|
} else {
|
|
set_fd_item_set(fd_item_set);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::create_fd_item_from_select_list(ObFdItemSet *fd_item_set)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSEArray<ObRawExpr*, 8> select_exprs;
|
|
ObTableFdItem *fd_item = NULL;
|
|
if (OB_ISNULL(fd_item_set) || OB_ISNULL(my_plan_) || OB_ISNULL(get_stmt()) ||
|
|
OB_UNLIKELY(!get_stmt()->is_select_stmt())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpect parameter", K(ret), K(fd_item_set), K(my_plan_), K(get_stmt()));
|
|
} else if (OB_FAIL(static_cast<const ObSelectStmt *>(get_stmt())->get_select_exprs(select_exprs))) {
|
|
LOG_WARN("failed to get select exprs", K(ret));
|
|
} else if (ObTransformUtils::need_compute_fd_item_set(select_exprs)) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < select_exprs.count(); ++i) {
|
|
ObSEArray<ObRawExpr *, 1> value_exprs;
|
|
if (OB_FAIL(value_exprs.push_back(select_exprs.at(i)))) {
|
|
LOG_WARN("failed to push back expr", K(ret));
|
|
} else if (OB_FAIL(my_plan_->get_fd_item_factory().create_table_fd_item(fd_item,
|
|
true,
|
|
value_exprs,
|
|
get_table_set()))) {
|
|
LOG_WARN("failed to create fd item", K(ret));
|
|
} else if (OB_FAIL(fd_item_set->push_back(fd_item))) {
|
|
LOG_WARN("failed to push back fd item", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::compute_op_ordering()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObLogicalOperator *child = NULL;
|
|
if (HASH_AGGREGATE == algo_) {
|
|
// do nothing
|
|
reset_op_ordering();
|
|
} else if (OB_ISNULL(child = get_child(ObLogicalOperator::first_child))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("child is null", K(ret));
|
|
} else if (has_rollup()) {
|
|
ObSEArray<OrderItem, 4> ordering;
|
|
// for rollup distributor, sort key is inner
|
|
if (ObRollupStatus::ROLLUP_DISTRIBUTOR != rollup_adaptive_info_.rollup_status_) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < group_exprs_.count(); i++) {
|
|
if (i < child->get_op_ordering().count() &&
|
|
child->get_op_ordering().at(i).expr_ == group_exprs_.at(i) &&
|
|
OB_FAIL(ordering.push_back(child->get_op_ordering().at(i)))) {
|
|
LOG_WARN("failed to push back into ordering.", K(ret));
|
|
} else {}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(set_op_ordering(ordering))) {
|
|
LOG_WARN("failed to set op ordering.", K(ret));
|
|
} else {
|
|
is_range_order_ = child->get_is_range_order();
|
|
is_local_order_ = is_fully_partition_wise() && !get_op_ordering().empty();
|
|
}
|
|
} else if (OB_FAIL(set_op_ordering(child->get_op_ordering()))) {
|
|
LOG_WARN("failed to set op ordering", K(ret));
|
|
} else {
|
|
is_range_order_ = child->get_is_range_order();
|
|
is_local_order_ = is_fully_partition_wise() && !get_op_ordering().empty();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::allocate_granule_pre(AllocGIContext &ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(pw_allocate_granule_pre(ctx))) {
|
|
LOG_WARN("failed to allocate partition wise granule", K(ret));
|
|
} else { /*do nothing*/ }
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::allocate_granule_post(AllocGIContext &ctx)
|
|
{
|
|
return pw_allocate_granule_post(ctx);
|
|
}
|
|
|
|
int ObLogGroupBy::compute_one_row_info()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (group_exprs_.empty() && rollup_exprs_.empty()) {
|
|
set_is_at_most_one_row(true);
|
|
} else if (has_rollup()) {
|
|
set_is_at_most_one_row(false);
|
|
} else if (OB_FAIL(ObLogicalOperator::compute_one_row_info())) {
|
|
LOG_WARN("failed to compute one row info", K(ret));
|
|
} else { /*do nothing*/ }
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::allocate_startup_expr_post()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (SCALAR_AGGREGATE == algo_) {
|
|
//do nothing
|
|
} else if (OB_FAIL(ObLogicalOperator::allocate_startup_expr_post())) {
|
|
LOG_WARN("failed to allocate startup exprs post", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::set_rollup_info(
|
|
const ObRollupStatus rollup_status,
|
|
ObRawExpr *rollup_id_expr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
rollup_adaptive_info_.rollup_id_expr_ = rollup_id_expr;
|
|
rollup_adaptive_info_.rollup_status_ = rollup_status;
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::set_rollup_info(
|
|
const ObRollupStatus rollup_status,
|
|
ObRawExpr *rollup_id_expr,
|
|
ObIArray<OrderItem> &sort_keys,
|
|
ObIArray<OrderItem> &ecd_sort_keys,
|
|
bool enable_encode_sort)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
rollup_adaptive_info_.rollup_id_expr_ = rollup_id_expr;
|
|
rollup_adaptive_info_.rollup_status_ = rollup_status;
|
|
rollup_adaptive_info_.enable_encode_sort_ = enable_encode_sort;
|
|
rollup_adaptive_info_.sort_keys_.reset();
|
|
rollup_adaptive_info_.ecd_sort_keys_.reset();
|
|
if (OB_FAIL(append(rollup_adaptive_info_.sort_keys_, sort_keys))) {
|
|
LOG_WARN("failed to append sort keys", K(ret));
|
|
} else if (OB_FAIL(append(rollup_adaptive_info_.ecd_sort_keys_, ecd_sort_keys))) {
|
|
LOG_WARN("failed to append sort keys", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObThreeStageAggrInfo::set_first_stage_info(ObRawExpr *aggr_code_expr,
|
|
ObIArray<ObDistinctAggrBatch> &batch,
|
|
double aggr_code_ndv)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
reuse();
|
|
aggr_stage_ = ObThreeStageAggrStage::FIRST_STAGE;
|
|
aggr_code_expr_ = aggr_code_expr;
|
|
distinct_aggr_count_ = 0;
|
|
aggr_code_ndv_ = aggr_code_ndv;
|
|
if (OB_FAIL(distinct_aggr_batch_.assign(batch))) {
|
|
LOG_WARN("failed to assign batch", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; i < batch.count(); ++i) {
|
|
distinct_aggr_count_ += batch.at(i).mocked_aggrs_.count();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObThreeStageAggrInfo::set_second_stage_info(ObRawExpr *aggr_code_expr,
|
|
ObIArray<ObDistinctAggrBatch> &batch,
|
|
ObIArray<ObRawExpr *> &distinct_exprs)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
reuse();
|
|
aggr_stage_ = ObThreeStageAggrStage::SECOND_STAGE;
|
|
aggr_code_expr_ = aggr_code_expr;
|
|
distinct_aggr_count_ = 0;
|
|
if (OB_FAIL(distinct_aggr_batch_.assign(batch))) {
|
|
LOG_WARN("failed to assign batch", K(ret));
|
|
} else if (OB_FAIL(distinct_exprs_.assign(distinct_exprs))) {
|
|
LOG_WARN("failed to assign distinct", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; i < batch.count(); ++i) {
|
|
distinct_aggr_count_ += batch.at(i).mocked_aggrs_.count();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObThreeStageAggrInfo::set_third_stage_info(ObRawExpr *aggr_code_expr,
|
|
ObIArray<ObDistinctAggrBatch> &batch)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
reuse();
|
|
aggr_stage_ = ObThreeStageAggrStage::THIRD_STAGE;
|
|
aggr_code_expr_ = aggr_code_expr;
|
|
distinct_aggr_count_ = 0;
|
|
if (OB_FAIL(distinct_aggr_batch_.assign(batch))) {
|
|
LOG_WARN("failed to assign batch", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; i < batch.count(); ++i) {
|
|
distinct_aggr_count_ += batch.at(i).mocked_aggrs_.count();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::set_three_stage_info(const ObThreeStageAggrInfo &info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(three_stage_info_.assign(info))) {
|
|
LOG_WARN("failed to assgin", K(ret));
|
|
} else if (is_third_stage()) {
|
|
// do nothing
|
|
} else if (!ObOptimizerUtil::find_item(group_exprs_,
|
|
three_stage_info_.aggr_code_expr_,
|
|
&three_stage_info_.aggr_code_idx_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("aggr code expr is not found", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::is_my_fixed_expr(const ObRawExpr *expr, bool &is_fixed)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_fixed = false;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret));
|
|
} else {
|
|
is_fixed = ObOptimizerUtil::find_item(aggr_exprs_, expr) ||
|
|
(T_FUN_SYS_REMOVE_CONST == expr->get_expr_type() && ObOptimizerUtil::find_item(rollup_exprs_, expr));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::compute_sharding_info()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (ObRollupStatus::ROLLUP_COLLECTOR == rollup_adaptive_info_.rollup_status_) {
|
|
ObLogicalOperator *child = NULL;
|
|
if (get_num_of_child() == 0) {
|
|
/*do nothing*/
|
|
} else if (OB_ISNULL(child = get_child(ObLogicalOperator::first_child))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (child->get_strong_sharding() != NULL &&
|
|
OB_FAIL(weak_sharding_.push_back(child->get_strong_sharding()))) {
|
|
LOG_WARN("failed to push back weak sharding");
|
|
} else if (OB_FAIL(append(weak_sharding_, child->get_weak_sharding()))) {
|
|
LOG_WARN("failed to assign sharding info", K(ret));
|
|
} else {
|
|
inherit_sharding_index_ = ObLogicalOperator::first_child;
|
|
strong_sharding_ = NULL;
|
|
}
|
|
} else if (OB_FAIL(ObLogicalOperator::compute_sharding_info())) {
|
|
LOG_WARN("failed to compute sharding info", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLogGroupBy::get_card_without_filter(double &card)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
card = get_distinct_card();
|
|
return ret;
|
|
} |