[CP] enhance rewrite minmax on index

This commit is contained in:
jingtaoye35
2023-07-07 09:12:06 +00:00
committed by ob-robot
parent c08774b940
commit e1528cc02d
2 changed files with 67 additions and 83 deletions

View File

@ -80,36 +80,39 @@ int ObTransformMinMax::check_transform_validity(ObSelectStmt *select_stmt,
bool &is_valid) bool &is_valid)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
const ObRawExpr *select_expr = NULL; const ObAggFunRawExpr *expr = NULL;
aggr_expr = NULL;
is_valid = false; is_valid = false;
if (OB_ISNULL(select_stmt)) { if (OB_ISNULL(select_stmt)) {
ret = OB_ERR_UNEXPECTED; ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(select_stmt)); LOG_WARN("unexpected null", K(ret), K(select_stmt));
} else if (select_stmt->has_recusive_cte() || select_stmt->has_hierarchical_query()) { } else if (select_stmt->has_recusive_cte() || select_stmt->has_hierarchical_query()) {
//do nothing
OPT_TRACE("stmt has recusive cte or hierarchical query"); OPT_TRACE("stmt has recusive cte or hierarchical query");
} else if (select_stmt->get_from_item_size() != 1 } else if (select_stmt->get_from_item_size() != 1 ||
|| select_stmt->get_from_item(0).is_joined_ select_stmt->get_from_item(0).is_joined_ ||
|| select_stmt->get_group_expr_size() > 0 select_stmt->get_aggr_item_size() != 1 ||
|| select_stmt->has_rollup() !select_stmt->is_scala_group_by()) {
|| select_stmt->get_aggr_item_size() != 1) {
//do nothing
OPT_TRACE("not a simple query"); OPT_TRACE("not a simple query");
} else if (OB_FAIL(is_valid_select_list(*select_stmt, select_expr, is_valid))) { } else if (OB_ISNULL(expr = select_stmt->get_aggr_items().at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("params have null", K(ret), KP(expr));
} else if ((T_FUN_MAX != expr->get_expr_type() && T_FUN_MIN != expr->get_expr_type()) ||
expr->get_real_param_count() != 1) {
OPT_TRACE("aggr expr is not min/max expr");
} else if (OB_FAIL(is_valid_index_column(select_stmt, expr->get_param_expr(0), is_valid))) {
LOG_WARN("failed to check is valid index column", K(ret));
} else if (!is_valid) {
OPT_TRACE("aggr expr is not include index column");
} else if (OB_FAIL(is_valid_select_list(*select_stmt, expr, is_valid))) {
LOG_WARN("failed to check is valid select list", K(ret)); LOG_WARN("failed to check is valid select list", K(ret));
} else if (!is_valid) { } else if (!is_valid) {
//do nothing OPT_TRACE("select list is const or aggr_expr");
OPT_TRACE("select expr is not single expr"); } else if (OB_FAIL(is_valid_having(select_stmt, expr, is_valid))) {
} else if (OB_FAIL(is_valid_aggr_expr(select_stmt, select_expr, aggr_expr, is_valid))) {
LOG_WARN("failed to check is valid expr", K(ret));
} else if (!is_valid) {
//do nothing
OPT_TRACE("select expr is not min/max expr");
} else if (OB_FAIL(is_valid_having(select_stmt, aggr_expr, is_valid))) {
LOG_WARN("fail to check is valid having", K(ret)); LOG_WARN("fail to check is valid having", K(ret));
} else if (!is_valid) { } else if (!is_valid) {
OPT_TRACE("having condition is invalid"); OPT_TRACE("having condition is invalid");
} else { } else {
aggr_expr = select_stmt->get_aggr_items().at(0);
LOG_TRACE("Succeed to check transform validity", K(is_valid)); LOG_TRACE("Succeed to check transform validity", K(is_valid));
} }
return ret; return ret;
@ -152,79 +155,68 @@ int ObTransformMinMax::do_transform(ObSelectStmt *select_stmt, ObAggFunRawExpr *
} }
int ObTransformMinMax::is_valid_select_list(const ObSelectStmt &stmt, int ObTransformMinMax::is_valid_select_list(const ObSelectStmt &stmt,
const ObRawExpr *&aggr_expr, const ObAggFunRawExpr *aggr_expr,
bool &is_valid) bool &is_valid)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
is_valid = false; is_valid = false;
int64_t num_non_const_exprs = 0; if (OB_ISNULL(aggr_expr)) {
aggr_expr = NULL; ret = OB_ERR_UNEXPECTED;
for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_select_item_size(); ++i) { LOG_WARN("params have null", K(ret), KP(aggr_expr));
const ObRawExpr *expr = stmt.get_select_item(i).expr_; } else {
if (OB_ISNULL(expr)) { for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_select_item_size(); ++i) {
ret = OB_ERR_UNEXPECTED; const ObRawExpr *expr = stmt.get_select_item(i).expr_;
LOG_WARN("expr should not be NULL", K(ret)); if (OB_ISNULL(expr)) {
} else if (expr->is_const_expr()) { ret = OB_ERR_UNEXPECTED;
/*do nothing */ LOG_WARN("expr should not be NULL", K(ret));
} else { } else if (expr->is_const_expr()) {
aggr_expr = expr; /* do nothing */
++num_non_const_exprs; } else if (OB_FAIL(is_valid_aggr_expr(stmt, expr, aggr_expr, is_valid))) {
LOG_WARN("failed to check expr is valid aggr", K(ret));
} else if (!is_valid) {
break;
}
} }
} }
if (OB_SUCC(ret) && num_non_const_exprs == 1) {
is_valid = true;
}
return ret; return ret;
} }
int ObTransformMinMax::is_valid_aggr_expr(const ObSelectStmt *stmt, int ObTransformMinMax::is_valid_aggr_expr(const ObSelectStmt &stmt,
const ObRawExpr *expr, const ObRawExpr *expr,
ObAggFunRawExpr *&column_aggr_expr, const ObAggFunRawExpr *aggr_expr,
bool &is_valid) bool &is_valid)
{ {
int ret = OB_SUCCESS; int ret = OB_SUCCESS;
bool is_stack_overflow = false; bool is_stack_overflow = false;
is_valid = false; is_valid = false;
if (OB_ISNULL(expr) || OB_ISNULL(stmt)) { const ObRawExpr *param = NULL;
if (OB_ISNULL(aggr_expr) || OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED; ret = OB_ERR_UNEXPECTED;
LOG_WARN("params have null", K(ret), K(expr), K(stmt)); LOG_WARN("expr should not be NULL", K(ret), KP(expr), KP(aggr_expr));
} else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) {
LOG_WARN("failed to check stack overflow", K(ret)); LOG_WARN("failed to check stack overflow", K(ret));
} else if (is_stack_overflow) { } else if (is_stack_overflow) {
ret = OB_SIZE_OVERFLOW; ret = OB_SIZE_OVERFLOW;
LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow));
} else if ((T_FUN_MAX == expr->get_expr_type() } else if (expr == aggr_expr) {
|| T_FUN_MIN == expr->get_expr_type())) { is_valid = true;
const ObAggFunRawExpr *aggr_expr =
static_cast<const ObAggFunRawExpr*>(expr);
if (1 == aggr_expr->get_real_param_count()) {
if (OB_FAIL(is_valid_index_column(stmt, aggr_expr->get_param_expr(0), is_valid))) {
LOG_WARN("failed to check is valid index column", K(ret));
} else if (is_valid) {
column_aggr_expr = const_cast<ObAggFunRawExpr *>(aggr_expr);
}
}
} else if (expr->has_flag(CNT_AGG)) { } else if (expr->has_flag(CNT_AGG)) {
const ObRawExpr *aggr_param = NULL;
const ObRawExpr *param = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
if (OB_ISNULL(param = expr->get_param_expr(i))) { if (OB_ISNULL(param = expr->get_param_expr(i))) {
ret = OB_ERR_UNEXPECTED; ret = OB_ERR_UNEXPECTED;
LOG_WARN("param is null", K(ret)); LOG_WARN("param is null", K(ret));
} else if (param->is_const_expr()) { } else if (param->is_const_expr()) {
/* do nothing */ /* do nothing */
} else if (param->has_flag(CNT_AGG) && OB_ISNULL(aggr_param)) { } else if (param->has_flag(CNT_AGG)) {
aggr_param = param; if (OB_FAIL(SMART_CALL(is_valid_aggr_expr(stmt, param, aggr_expr, is_valid)))) {
} else { // not valid LOG_WARN("failed to check is_valid_expr", K(ret));
aggr_param = NULL; } else if (!is_valid) {
break;
}
} else {
break; break;
} }
} }
if (OB_ISNULL(aggr_param)) {
// do nothing
} else if (OB_FAIL(SMART_CALL(is_valid_aggr_expr(stmt, aggr_param, column_aggr_expr, is_valid)))) {
LOG_WARN("failed to check is_valid_expr", K(ret));
}
} }
return ret; return ret;
} }

View File

@ -44,17 +44,17 @@ class ObOpRawExpr;
class ObColumnRefRawExpr; class ObColumnRefRawExpr;
class ObAggFunRawExpr; class ObAggFunRawExpr;
// 1. 针对列的 min/max 聚合 /* rewrite min or max aggr on index as a subquery which can table scan just one line.
//select中含有max和min时,尝试消除max和min,添加order by 和limit * eg:
//例如: * select min(pk) from t1
// 原始语句: select min(c2) from t1; * -->
// 转换后:select min(c2) from (select c2 from t2 where c2 is not null order by c2 limit 1) as t; * select min(v.c1) from (select pk from t1 where pk is not null order by pk limit 1)
// *
//转换原则: * rewrite requests:
// a. max或min中是表的某一列;且该列某个索引前缀中的第一个非常量的列 * 1. max/min aggragate on a column of table, and this column is a index or the first nonconst column of index.
// b. select语句中不含有limit和group by语句 * 2. select stmt is scalar group by and hasn't limit.
// c. 只处理单表情况 * 3. just deal single table yet.
// */
class ObTransformMinMax : public ObTransformRule class ObTransformMinMax : public ObTransformRule
{ {
public: public:
@ -79,9 +79,9 @@ private:
const ObAggFunRawExpr *column_aggr_expr, const ObAggFunRawExpr *column_aggr_expr,
bool &is_expected); bool &is_expected);
int is_valid_aggr_expr(const ObSelectStmt *stmt, int is_valid_aggr_expr(const ObSelectStmt &stmt,
const ObRawExpr *expr, const ObRawExpr *expr,
ObAggFunRawExpr *&column_aggr_expr, const ObAggFunRawExpr *aggr_expr,
bool &is_valid); bool &is_valid);
int find_unexpected_having_expr(const ObAggFunRawExpr *aggr_expr, int find_unexpected_having_expr(const ObAggFunRawExpr *aggr_expr,
@ -93,18 +93,10 @@ private:
int set_child_order_item(ObSelectStmt *stmt, ObRawExpr *aggr_expr); int set_child_order_item(ObSelectStmt *stmt, ObRawExpr *aggr_expr);
/** /**
* @brief: 检查select item中是否至多包含一个非常数列,并存到is_valid中, * @brief: check whether there is any valid select_item
* 改写要求select item只有一项聚集函数,其它的列只能是常量。 * request stmt has only one valid aggr expr, and select_items are exprs combainded const expr or that aggr_expr
*
* @param[in] stmt 待检查的表达式
* @param[out] is_valid 是否至多包含一个非常数列
*
* 副作用:
* 将遇到的第一个非常数select item 记录在 idx_aggr_column_中,如果is_valid
* 为true,最终会记录唯一的聚集函数的select item中的索引,如果全都为常量,则置为0
*
*/ */
int is_valid_select_list(const ObSelectStmt &stmt, const ObRawExpr *&aggr_expr, bool &is_valid); int is_valid_select_list(const ObSelectStmt &stmt, const ObAggFunRawExpr *aggr_expr, bool &is_valid);
DISALLOW_COPY_AND_ASSIGN(ObTransformMinMax); DISALLOW_COPY_AND_ASSIGN(ObTransformMinMax);
}; };