fix mysql calc found rows bug, adjust semi condition check

This commit is contained in:
zs0 2022-03-16 20:17:12 +08:00 committed by LINxiansheng
parent 8d81ad6ed1
commit 996696c528
11 changed files with 90 additions and 141 deletions

View File

@ -1144,39 +1144,35 @@ int ObCodeGeneratorImpl::convert_limit(ObLogLimit& op, const PhyOpsDesc& child_o
ObSqlExpression* limit_expr = NULL;
ObSqlExpression* offset_expr = NULL;
ObSqlExpression* percent_expr = NULL;
if (OB_FAIL(op.need_calc_found_rows(need_calc))) {
LOG_WARN("need_calc_found_rows() fails unexpectedly", K(ret));
} else {
phy_op->set_calc_found_rows(need_calc);
phy_op->set_is_top_limit(op.is_top_limit());
phy_op->set_is_fetch_with_ties(op.is_fetch_with_ties());
limit_raw_expr = op.get_limit_count();
offset_raw_expr = op.get_limit_offset();
percent_raw_expr = op.get_limit_percent();
if (NULL != limit_raw_expr) {
if (OB_FAIL(generate_sql_expr(
phy_op->get_sql_expression_factory(), limit_raw_expr, *child_ops.at(0).second, limit_expr))) {
LOG_WARN("Generation of sql expression fails", K(ret));
}
phy_op->set_calc_found_rows(op.get_is_calc_found_rows());
phy_op->set_is_top_limit(op.is_top_limit());
phy_op->set_is_fetch_with_ties(op.is_fetch_with_ties());
limit_raw_expr = op.get_limit_count();
offset_raw_expr = op.get_limit_offset();
percent_raw_expr = op.get_limit_percent();
if (NULL != limit_raw_expr) {
if (OB_FAIL(generate_sql_expr(
phy_op->get_sql_expression_factory(), limit_raw_expr, *child_ops.at(0).second, limit_expr))) {
LOG_WARN("Generation of sql expression fails", K(ret));
}
}
if (OB_SUCC(ret) && NULL != offset_raw_expr) {
if (OB_FAIL(generate_sql_expr(
phy_op->get_sql_expression_factory(), offset_raw_expr, *child_ops.at(0).second, offset_expr))) {
LOG_WARN("Generation of sql expression fails", K(ret));
}
if (OB_SUCC(ret) && NULL != offset_raw_expr) {
if (OB_FAIL(generate_sql_expr(
phy_op->get_sql_expression_factory(), offset_raw_expr, *child_ops.at(0).second, offset_expr))) {
LOG_WARN("Generation of sql expression fails", K(ret));
}
}
if (OB_SUCC(ret) && NULL != percent_raw_expr) {
if (OB_FAIL(generate_sql_expr(
phy_op->get_sql_expression_factory(), percent_raw_expr, *child_ops.at(0).second, percent_expr))) {
LOG_WARN("Generation of sql expression fails", K(ret));
}
if (OB_SUCC(ret) && NULL != percent_raw_expr) {
if (OB_FAIL(generate_sql_expr(
phy_op->get_sql_expression_factory(), percent_raw_expr, *child_ops.at(0).second, percent_expr))) {
LOG_WARN("Generation of sql expression fails", K(ret));
}
if (OB_SUCC(ret) && op.is_fetch_with_ties()) {
if (OB_FAIL(set_sort_columns_for_fetch(phy_op, input_row_desc, op.get_expected_ordering()))) {
LOG_WARN("failed to set limit sort columns for fetch", K(ret));
}
}
if (OB_SUCC(ret) && op.is_fetch_with_ties()) {
if (OB_FAIL(set_sort_columns_for_fetch(phy_op, input_row_desc, op.get_expected_ordering()))) {
LOG_WARN("failed to set limit sort columns for fetch", K(ret));
}
}

View File

@ -587,36 +587,33 @@ int ObStaticEngineCG::generate_spec(ObLogLimit& op, ObLimitSpec& spec, const boo
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(op.need_calc_found_rows(spec.calc_found_rows_))) {
LOG_WARN("get calc found rows failed", K(ret));
} else {
spec.is_top_limit_ = op.is_top_limit();
spec.is_fetch_with_ties_ = op.is_fetch_with_ties();
if (NULL != op.get_limit_count()) {
CK(op.get_limit_count()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_limit_count(), spec.limit_expr_));
OZ(mark_expr_self_produced(op.get_limit_count()));
}
if (NULL != op.get_limit_offset()) {
CK(op.get_limit_offset()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_limit_offset(), spec.offset_expr_));
OZ(mark_expr_self_produced(op.get_limit_offset()));
}
if (NULL != op.get_limit_percent()) {
CK(op.get_limit_percent()->get_result_type().is_double());
OZ(generate_rt_expr(*op.get_limit_percent(), spec.percent_expr_));
OZ(mark_expr_self_produced(op.get_limit_percent()));
}
if (OB_SUCC(ret) && op.is_fetch_with_ties()) {
OZ(spec.sort_columns_.init(op.get_expected_ordering().count()));
FOREACH_CNT_X(it, op.get_expected_ordering(), OB_SUCC(ret))
{
CK(NULL != it->expr_);
ObExpr* e = NULL;
OZ(generate_rt_expr(*it->expr_, e));
OZ(mark_expr_self_produced(it->expr_));
OZ(spec.sort_columns_.push_back(e));
}
spec.calc_found_rows_ = op.get_is_calc_found_rows();
spec.is_top_limit_ = op.is_top_limit();
spec.is_fetch_with_ties_ = op.is_fetch_with_ties();
if (NULL != op.get_limit_count()) {
CK(op.get_limit_count()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_limit_count(), spec.limit_expr_));
OZ(mark_expr_self_produced(op.get_limit_count()));
}
if (NULL != op.get_limit_offset()) {
CK(op.get_limit_offset()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_limit_offset(), spec.offset_expr_));
OZ(mark_expr_self_produced(op.get_limit_offset()));
}
if (NULL != op.get_limit_percent()) {
CK(op.get_limit_percent()->get_result_type().is_double());
OZ(generate_rt_expr(*op.get_limit_percent(), spec.percent_expr_));
OZ(mark_expr_self_produced(op.get_limit_percent()));
}
if (OB_SUCC(ret) && op.is_fetch_with_ties()) {
OZ(spec.sort_columns_.init(op.get_expected_ordering().count()));
FOREACH_CNT_X(it, op.get_expected_ordering(), OB_SUCC(ret))
{
CK(NULL != it->expr_);
ObExpr* e = NULL;
OZ(generate_rt_expr(*it->expr_, e));
OZ(mark_expr_self_produced(it->expr_));
OZ(spec.sort_columns_.push_back(e));
}
}
return ret;
@ -696,8 +693,6 @@ int ObStaticEngineCG::generate_spec(
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null pointer", K(ret));
} else if (raw_expr->has_flag(IS_CONST) || raw_expr->has_flag(IS_CONST_EXPR)) {
// distinct const value, 这里需要注意:distinct 1被跳过了,
// 但ObMergeDistinct中,如果没有distinct列,则默认所有值都相等,这个语义正好是符合预期的。
continue;
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
@ -717,7 +712,7 @@ int ObStaticEngineCG::generate_spec(
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(
expr->datum_meta_.type_,
expr->datum_meta_.type_,
NULL_LAST,//这里null last还是first无所谓
NULL_LAST,
expr->datum_meta_.cs_type_,
lib::is_oracle_mode());
ObHashFunc hash_func;
@ -746,8 +741,6 @@ int ObStaticEngineCG::generate_spec(
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null pointer", K(ret));
} else if (raw_expr->has_flag(IS_CONST) || raw_expr->has_flag(IS_CONST_EXPR)) {
// distinct const value, 这里需要注意:distinct 1被跳过了,
// 但ObMergeDistinct中,如果没有distinct列,则默认所有值都相等,这个语义正好是符合预期的。
continue;
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));

View File

@ -36,8 +36,7 @@ int ObLogLimit::copy_without_child(ObLogicalOperator*& out)
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to cast ObLogicalOperator * to ObLogLimit *", K(ret));
} else {
limit->set_calc_found_rows(is_calc_found_rows_);
limit->set_has_union_child(has_union_child_);
limit->set_is_calc_found_rows(is_calc_found_rows_);
limit->set_fetch_with_ties(is_fetch_with_ties());
limit->set_limit_count(limit_count_);
limit->set_limit_offset(limit_offset_);
@ -239,7 +238,6 @@ uint64_t ObLogLimit::hash(uint64_t seed) const
{
uint64_t hash_value = seed;
hash_value = do_hash(is_calc_found_rows_, hash_value);
hash_value = do_hash(has_union_child_, hash_value);
hash_value = do_hash(is_top_limit_, hash_value);
hash_value = ObOptimizerUtil::hash_expr(limit_count_, hash_value);
hash_value = ObOptimizerUtil::hash_expr(limit_offset_, hash_value);

View File

@ -21,7 +21,6 @@ public:
ObLogLimit(ObLogPlan& plan)
: ObLogicalOperator(plan),
is_calc_found_rows_(false),
has_union_child_(false),
is_top_limit_(false),
is_fetch_with_ties_(false),
limit_count_(NULL),
@ -55,26 +54,11 @@ public:
{
limit_percent_ = limit_percent;
}
void set_calc_found_rows(bool found_rows)
void set_is_calc_found_rows(bool found_rows)
{
is_calc_found_rows_ = found_rows;
}
int need_calc_found_rows(bool& need_calc)
{
int ret = common::OB_SUCCESS;
need_calc = false;
if (is_top_limit_ && is_calc_found_rows_) {
need_calc = true;
} else if (is_top_limit_ && has_union_child_) {
need_calc = true;
} else { /* Do nothing */
}
return ret;
}
void set_has_union_child(bool has_union_child)
{
has_union_child_ = has_union_child;
}
bool get_is_calc_found_rows() { return is_calc_found_rows_; }
void set_top_limit(bool is_top_limit)
{
is_top_limit_ = is_top_limit;
@ -83,10 +67,6 @@ public:
{
return is_top_limit_;
}
bool has_union_child()
{
return has_union_child_;
}
virtual int est_cost() override;
virtual int allocate_granule_pre(AllocGIContext &ctx) override;
virtual int allocate_granule_post(AllocGIContext &ctx) override;
@ -110,7 +90,6 @@ public:
private:
bool is_calc_found_rows_;
bool has_union_child_;
bool is_top_limit_;
bool is_fetch_with_ties_;
ObRawExpr* limit_count_;

View File

@ -5030,34 +5030,24 @@ int ObLogPlan::candi_allocate_limit(ObIArray<OrderItem>& order_items)
{
int ret = OB_SUCCESS;
ObDMLStmt* stmt = NULL;
bool has_union_child = false;
if (OB_ISNULL(stmt = get_stmt())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get unexpected null", K(get_stmt()), K(ret));
} else if (stmt->is_set_stmt()) {
has_union_child = static_cast<ObSelectStmt*>(stmt)->get_set_op() == ObSelectStmt::UNION;
} else { /*do nothing*/
}
if (OB_SUCC(ret)) {
if (OB_FAIL(candi_allocate_limit(stmt->get_limit_expr(),
stmt->get_offset_expr(),
stmt->get_limit_percent_expr(),
order_items,
has_union_child,
stmt->is_calc_found_rows(),
stmt->has_top_limit(),
stmt->is_fetch_with_ties()))) {
LOG_WARN("failed to allocate limit operator", K(ret));
} else { /*do nothing*/
}
}
} else if (OB_FAIL(candi_allocate_limit(stmt->get_limit_expr(),
stmt->get_offset_expr(),
stmt->get_limit_percent_expr(),
order_items,
stmt->is_calc_found_rows(),
stmt->has_top_limit(),
stmt->is_fetch_with_ties()))) {
LOG_WARN("failed to allocate limit operator", K(ret));
} else { /*do nothing*/}
return ret;
}
int ObLogPlan::candi_allocate_limit(ObRawExpr* limit_expr, ObRawExpr* offset_expr, ObRawExpr* percent_expr,
ObIArray<OrderItem>& expect_ordering, const bool has_union_child, const bool is_calc_found_rows,
const bool is_top_limit, const bool is_fetch_with_ties)
ObIArray<OrderItem>& expect_ordering, const bool is_calc_found_rows, const bool is_top_limit,
const bool is_fetch_with_ties)
{
int ret = OB_SUCCESS;
CandidatePlan temp_plan;
@ -5108,7 +5098,6 @@ int ObLogPlan::candi_allocate_limit(ObRawExpr* limit_expr, ObRawExpr* offset_exp
offset_expr,
percent_expr,
expect_ordering,
has_union_child,
is_calc_found_rows,
is_top_limit,
is_fetch_with_ties))) {
@ -5320,8 +5309,8 @@ int ObLogPlan::if_plan_need_limit(ObLogicalOperator* top, ObRawExpr* limit_expr,
}
int ObLogPlan::allocate_limit_as_top(ObLogicalOperator*& old_top, ObRawExpr* limit_expr, ObRawExpr* offset_expr,
ObRawExpr* percent_expr, ObIArray<OrderItem>& expect_ordering, const bool has_union_child,
const bool is_calc_found_rows, const bool is_top_limit, const bool is_fetch_with_ties)
ObRawExpr* percent_expr, ObIArray<OrderItem>& expect_ordering, const bool is_calc_found_rows,
const bool is_top_limit, const bool is_fetch_with_ties)
{
int ret = OB_SUCCESS;
ObLogLimit* limit = NULL;
@ -5336,8 +5325,7 @@ int ObLogPlan::allocate_limit_as_top(ObLogicalOperator*& old_top, ObRawExpr* lim
limit->set_limit_offset(offset_expr);
limit->set_limit_percent(percent_expr);
limit->set_child(ObLogicalOperator::first_child, old_top);
limit->set_has_union_child(has_union_child);
limit->set_calc_found_rows(is_calc_found_rows);
limit->set_is_calc_found_rows(is_calc_found_rows);
limit->set_top_limit(is_top_limit);
limit->set_fetch_with_ties(is_fetch_with_ties);
if (OB_FAIL(limit->set_expected_ordering(expect_ordering))) {

View File

@ -640,8 +640,8 @@ public:
/** @brief Allocate LIMIT on top of plan candidates */
int candi_allocate_limit(common::ObIArray<OrderItem>& order_items);
int candi_allocate_limit(ObRawExpr* limit_expr, ObRawExpr* offset_expr, ObRawExpr* percent_expr,
common::ObIArray<OrderItem>& expect_ordering, const bool has_union_child, const bool is_calc_found_rows,
const bool is_top_limit, const bool is_fetch_with_ties);
common::ObIArray<OrderItem>& expect_ordering, const bool is_calc_found_rows, const bool is_top_limit,
const bool is_fetch_with_ties);
int is_plan_reliable(const ObLogicalOperator* root, bool& is_reliable);
@ -660,8 +660,8 @@ public:
/** @brief allocate limit as new top(parent)**/
int allocate_limit_as_top(ObLogicalOperator*& old_top, ObRawExpr* limit_expr, ObRawExpr* offset_expr,
ObRawExpr* percent_expr, common::ObIArray<OrderItem>& expect_ordering, const bool has_union_child,
const bool is_calc_found_rows, const bool is_top_limit, const bool is_fetch_with_ties);
ObRawExpr* percent_expr, common::ObIArray<OrderItem>& expect_ordering, const bool is_calc_found_rows,
const bool is_top_limit, const bool is_fetch_with_ties);
/**
* Plan tree traversing(both top-down and bottom-up)

View File

@ -2014,12 +2014,9 @@ int ObLogicalOperator::set_sort_topn()
OB_ISNULL(session = optm_ctx->get_session_info())) {
LOG_WARN("get unexpected null", K(get_plan()), K(optm_ctx), K(session), K(ret));
} else if (LOG_LIMIT == get_type()) {
bool need_calc = false;
ObLogLimit* op_limit = static_cast<ObLogLimit*>(this);
is_fetch_with_ties = op_limit->is_fetch_with_ties();
if (OB_FAIL(op_limit->need_calc_found_rows(need_calc))) {
LOG_WARN("call need_calc_found_rows failed", K(ret));
} else if (need_calc) {
if (op_limit->get_is_calc_found_rows()) {
/*do nothing*/
} else {
limit_count_expr = op_limit->get_limit_count();

View File

@ -359,7 +359,7 @@ int ObSelectLogPlan::candi_allocate_distinct()
} else if (OB_ISNULL(limit_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("limit_expr is null", K(ret));
} else if (OB_FAIL(candi_allocate_limit(limit_expr, NULL, NULL, dummy_order_items, false, false, false, false))) {
} else if (OB_FAIL(candi_allocate_limit(limit_expr, NULL, NULL, dummy_order_items, false, false, false))) {
LOG_WARN("failed to allocate limit operator", K(ret));
} else { /*do nothing*/
}

View File

@ -277,11 +277,9 @@ int ObTransformSemiToInner::check_semi_join_condition(ObDMLStmt& stmt, SemiInfo&
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null expr", K(ret));
} else if (left_table_set.is_superset(expr->get_relation_ids())) {
// do nothing for left filters
} else if (right_table_set.is_superset(expr->get_relation_ids())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected semi condition", K(ret), K(*expr));
} else if (left_table_set.is_superset(expr->get_relation_ids()) ||
right_table_set.is_superset(expr->get_relation_ids())) {
// do nothing for left/right filters
} else if (T_OP_EQ != expr->get_expr_type()) {
is_all_equal_cond = false;
} else if (OB_ISNULL(left = expr->get_param_expr(0)) || OB_ISNULL(right = expr->get_param_expr(1))) {

View File

@ -607,7 +607,7 @@ SQL: select c1 from t1 union all select c1 from t2 order by c1 limit 1;
|ID|OPERATOR |NAME|EST. ROWS|COST|
--------------------------------------
|0 |LIMIT | |1 |74 |
|1 | SORT | |1 |74 |
|1 | TOP-N SORT | |1 |74 |
|2 | UNION ALL | |2 |73 |
|3 | TABLE SCAN|t1 |1 |36 |
|4 | TABLE SCAN|t2 |1 |36 |
@ -616,7 +616,7 @@ SQL: select c1 from t1 union all select c1 from t2 order by c1 limit 1;
Outputs & filters:
-------------------------------------
0 - output([UNION([1])]), filter(nil), limit(1), offset(nil)
1 - output([UNION([1])]), filter(nil), sort_keys([UNION([1]), ASC])
1 - output([UNION([1])]), filter(nil), sort_keys([UNION([1]), ASC]), topn(1)
2 - output([UNION([1])]), filter(nil)
3 - output([t1.c1]), filter(nil),
access([t1.c1]), partitions(p0),
@ -631,7 +631,7 @@ SQL: select c2 from t2 union all select c2 from t3 order by c2 limit 1;
|ID|OPERATOR |NAME|EST. ROWS|COST|
----------------------------------------
|0 |LIMIT | |1 |228 |
|1 | SORT | |1 |228 |
|1 | TOP-N SORT | |1 |228 |
|2 | UNION ALL | |2 |227 |
|3 | LIMIT | |1 |113 |
|4 | TOP-N SORT | |1 |113 |
@ -644,7 +644,7 @@ SQL: select c2 from t2 union all select c2 from t3 order by c2 limit 1;
Outputs & filters:
-------------------------------------
0 - output([UNION([1])]), filter(nil), limit(1), offset(nil)
1 - output([UNION([1])]), filter(nil), sort_keys([UNION([1]), ASC])
1 - output([UNION([1])]), filter(nil), sort_keys([UNION([1]), ASC]), topn(1)
2 - output([UNION([1])]), filter(nil)
3 - output([t2.c2]), filter(nil), limit(1), offset(nil)
4 - output([t2.c2]), filter(nil), sort_keys([t2.c2, ASC]), topn(1)
@ -705,7 +705,7 @@ SQL: (select c2, c3 from t2) union all (select c2, c3 from t3 order by c3) order
|ID|OPERATOR |NAME|EST. ROWS|COST|
----------------------------------------
|0 |LIMIT | |1 |308 |
|1 | SORT | |1 |307 |
|1 | TOP-N SORT | |1 |307 |
|2 | UNION ALL | |2 |306 |
|3 | LIMIT | |1 |153 |
|4 | TOP-N SORT | |1 |153 |
@ -718,7 +718,7 @@ SQL: (select c2, c3 from t2) union all (select c2, c3 from t3 order by c3) order
Outputs & filters:
-------------------------------------
0 - output([UNION([1])], [UNION([2])]), filter(nil), limit(1), offset(nil)
1 - output([UNION([1])], [UNION([2])]), filter(nil), sort_keys([UNION([1]), ASC])
1 - output([UNION([1])], [UNION([2])]), filter(nil), sort_keys([UNION([1]), ASC]), topn(1)
2 - output([UNION([1])], [UNION([2])]), filter(nil)
3 - output([t2.c2], [t2.c3]), filter(nil), limit(1), offset(nil)
4 - output([t2.c2], [t2.c3]), filter(nil), sort_keys([t2.c2, ASC]), topn(1)

View File

@ -179,7 +179,7 @@ SQL: select c1 from t1 union all select c2 from t2 order by c1 limit 2;
|ID|OPERATOR |NAME|EST. ROWS|COST|
----------------------------------------
|0 |LIMIT | |2 |161 |
|1 | SORT | |2 |161 |
|1 | TOP-N SORT | |2 |161 |
|2 | UNION ALL | |4 |159 |
|3 | TABLE SCAN |t1 |2 |37 |
|4 | LIMIT | |2 |122 |
@ -190,7 +190,7 @@ SQL: select c1 from t1 union all select c2 from t2 order by c1 limit 2;
Outputs & filters:
-------------------------------------
0 - output([UNION([1])]), filter(nil), limit(2), offset(nil)
1 - output([UNION([1])]), filter(nil), sort_keys([UNION([1]), ASC])
1 - output([UNION([1])]), filter(nil), sort_keys([UNION([1]), ASC]), topn(2)
2 - output([UNION([1])]), filter(nil)
3 - output([t1.c1]), filter(nil),
access([t1.c1]), partitions(p0),
@ -206,7 +206,7 @@ SQL: select c1, c2 from t1 order by c2 union all select c1, c2 from t2 order by
|ID|OPERATOR |NAME|EST. ROWS|COST|
--------------------------------------
|0 |LIMIT | |2 |77 |
|1 | SORT | |2 |76 |
|1 | TOP-N SORT | |2 |76 |
|2 | UNION ALL | |4 |74 |
|3 | TABLE SCAN|t1 |2 |37 |
|4 | TABLE SCAN|t2 |2 |37 |
@ -215,7 +215,7 @@ SQL: select c1, c2 from t1 order by c2 union all select c1, c2 from t2 order by
Outputs & filters:
-------------------------------------
0 - output([UNION([1])], [UNION([2])]), filter(nil), limit(2), offset(nil)
1 - output([UNION([1])], [UNION([2])]), filter(nil), sort_keys([UNION([1]), ASC])
1 - output([UNION([1])], [UNION([2])]), filter(nil), sort_keys([UNION([1]), ASC]), topn(2)
2 - output([UNION([1])], [UNION([2])]), filter(nil)
3 - output([t1.c1], [t1.c2]), filter(nil),
access([t1.c1], [t1.c2]), partitions(p0),
@ -230,7 +230,7 @@ SQL: select c1, c2 from t1 limit 5 union all select c1, c2 from t2 order by c1 l
|ID|OPERATOR |NAME|EST. ROWS|COST|
--------------------------------------
|0 |LIMIT | |2 |79 |
|1 | SORT | |2 |79 |
|1 | TOP-N SORT | |2 |79 |
|2 | UNION ALL | |7 |76 |
|3 | TABLE SCAN|t1 |5 |37 |
|4 | TABLE SCAN|t2 |2 |37 |
@ -239,7 +239,7 @@ SQL: select c1, c2 from t1 limit 5 union all select c1, c2 from t2 order by c1 l
Outputs & filters:
-------------------------------------
0 - output([UNION([1])], [UNION([2])]), filter(nil), limit(2), offset(nil)
1 - output([UNION([1])], [UNION([2])]), filter(nil), sort_keys([UNION([1]), ASC])
1 - output([UNION([1])], [UNION([2])]), filter(nil), sort_keys([UNION([1]), ASC]), topn(2)
2 - output([UNION([1])], [UNION([2])]), filter(nil)
3 - output([t1.c1], [t1.c2]), filter(nil),
access([t1.c1], [t1.c2]), partitions(p0),