diff --git a/src/sql/code_generator/ob_code_generator_impl.cpp b/src/sql/code_generator/ob_code_generator_impl.cpp index c072bb705a..79d730db41 100644 --- a/src/sql/code_generator/ob_code_generator_impl.cpp +++ b/src/sql/code_generator/ob_code_generator_impl.cpp @@ -971,10 +971,11 @@ int ObCodeGeneratorImpl::recursive_get_column_expr(const ObColumnRefRawExpr*& co if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); - } else if (!table_item->is_generated_table()) { - column = inner_column; - } else if (OB_FAIL(recursive_get_column_expr(column, *table_item))) { + } else if (table_item->is_generated_table() && + OB_FAIL(recursive_get_column_expr(inner_column, *table_item))) { LOG_WARN("faield to recursive get column expr", K(ret)); + } else { + column = inner_column; } } } diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 1be7b16ed9..d1e90555f3 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -5165,10 +5165,11 @@ int ObStaticEngineCG::recursive_get_column_expr(const ObColumnRefRawExpr*& colum if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); - } else if (!table_item->is_generated_table()) { - column = inner_column; - } else if (OB_FAIL(recursive_get_column_expr(column, *table_item))) { + } else if (table_item->is_generated_table() && + OB_FAIL(recursive_get_column_expr(inner_column, *table_item))) { LOG_WARN("faield to recursive get column expr", K(ret)); + } else { + column = inner_column; } } } diff --git a/src/sql/optimizer/ob_fd_item.cpp b/src/sql/optimizer/ob_fd_item.cpp index f691e726d1..4b81e8975f 100644 --- a/src/sql/optimizer/ob_fd_item.cpp +++ b/src/sql/optimizer/ob_fd_item.cpp @@ -112,6 +112,8 @@ int ObTableFdItem::check_expr_in_child(const ObRawExpr* expr, const EqualSets& e if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null expr", K(ret)); + } else if (expr->has_flag(CNT_AGG)) { + //do nothing } else if (expr->get_expr_levels().has_member(stmt_level_)) { if (child_tables_.is_superset(expr->get_relation_ids())) { is_in_child = true; diff --git a/src/sql/optimizer/ob_log_plan.cpp b/src/sql/optimizer/ob_log_plan.cpp index 4c5b300655..331cc21031 100644 --- a/src/sql/optimizer/ob_log_plan.cpp +++ b/src/sql/optimizer/ob_log_plan.cpp @@ -1590,12 +1590,12 @@ int ObLogPlan::pushdown_on_conditions( if (OB_ISNULL(qual = joined_table->join_conditions_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(qual), K(ret)); - } else if (RIGHT_OUTER_JOIN == join_type && !qual->get_relation_ids().is_empty() && + } else if (RIGHT_OUTER_JOIN == join_type && qual->get_relation_ids().is_subset(left_table_set)) { if (OB_FAIL(left_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); } - } else if (LEFT_OUTER_JOIN == join_type && !qual->get_relation_ids().is_empty() && + } else if (LEFT_OUTER_JOIN == join_type && qual->get_relation_ids().is_subset(right_table_set)) { if (OB_FAIL(right_quals.push_back(qual))) { LOG_WARN("failed to push back expr", K(ret)); diff --git a/src/sql/rewrite/ob_transform_full_outer_join.cpp b/src/sql/rewrite/ob_transform_full_outer_join.cpp index dd3faba9b9..ccfa3352cc 100644 --- a/src/sql/rewrite/ob_transform_full_outer_join.cpp +++ b/src/sql/rewrite/ob_transform_full_outer_join.cpp @@ -89,7 +89,7 @@ int ObTransformFullOuterJoin::recursively_eliminate_full_join( ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null.", K(ret)); } else if (table_item->type_ == TableItem::JOINED_TABLE) { - bool has_equal = false; + bool is_valid = false; JoinedTable* joined_table = static_cast(table_item); if (OB_ISNULL(joined_table->left_table_) || OB_ISNULL(joined_table->right_table_)) { ret = OB_ERR_UNEXPECTED; @@ -100,11 +100,9 @@ int ObTransformFullOuterJoin::recursively_eliminate_full_join( LOG_WARN("failed to transform full nl join.", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_single_table_ids(joined_table))) { LOG_WARN("failed to adjust single table ids.", K(ret)); - } else if (!joined_table->is_full_join()) { - /* do nothing */ - } else if (OB_FAIL(check_join_condition(stmt, joined_table, has_equal))) { + } else if (OB_FAIL(check_full_nl_valid(*stmt, joined_table, is_valid))) { LOG_WARN("failed to check join condition", K(ret)); - } else if (has_equal) { + } else if (!is_valid) { /* do nothing */ } else if (OB_FAIL(create_view_for_full_nl_join(stmt, joined_table, table_item))) { LOG_WARN("failed to create view for full nl join.", K(ret)); @@ -118,17 +116,54 @@ int ObTransformFullOuterJoin::recursively_eliminate_full_join( return ret; } -int ObTransformFullOuterJoin::check_join_condition(ObDMLStmt* stmt, JoinedTable* table, bool& has_equal) +int ObTransformFullOuterJoin::check_full_nl_valid(ObDMLStmt &stmt, TableItem* table_item, bool &is_valid) +{ + int ret = OB_SUCCESS; + is_valid = true; + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null joined table.", K(ret)); + } else if (table_item->type_ != TableItem::JOINED_TABLE) { + is_valid = false; + } else { + JoinedTable *joined_table = static_cast(table_item); + bool has_euqal = false; + bool has_subquery = false; + if (FULL_OUTER_JOIN != joined_table->joined_type_) { + is_valid = false; + } else if (OB_FAIL(check_join_condition(&stmt, + joined_table, + has_euqal, + has_subquery))) { + LOG_WARN("failed to check join condition", K(ret)); + } else if (has_euqal) { + is_valid = false; + } else if (has_subquery) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("full join on subquery not support now!", K(ret)); + } + } + return ret; +} + +int ObTransformFullOuterJoin::check_join_condition(ObDMLStmt* stmt, + JoinedTable* table, + bool &has_equal, + bool &has_subquery) { int ret = OB_SUCCESS; ObSEArray left_tables; ObSEArray right_tables; ObSEArray table_ids; - TableItem* left_table = NULL; - TableItem* right_table = NULL; + ObSEArray left_table_ids; + ObSEArray right_table_ids; + TableItem *left_table = NULL; + TableItem *right_table = NULL; has_equal = false; - if (OB_ISNULL(stmt) || OB_ISNULL(table) || OB_ISNULL(left_table = table->left_table_) || - OB_ISNULL(right_table = table->right_table_)) { + has_subquery = false; + if (OB_ISNULL(stmt) || OB_ISNULL(table) || + OB_ISNULL(left_table = table->left_table_) || + OB_ISNULL(right_table = table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else if (left_table->is_joined_table() && @@ -146,17 +181,38 @@ int ObTransformFullOuterJoin::check_join_condition(ObDMLStmt* stmt, JoinedTable* ObRawExpr* cond = table->join_conditions_.at(i); table_ids.reuse(); if (OB_ISNULL(cond)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpect null condition", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::extract_table_ids(cond, table_ids))) { - LOG_WARN("failed to extract table ids", K(ret)); - } else if (table_ids.empty()) { - // do nothing - } else if (cond->has_flag(IS_JOIN_COND) && ObOptimizerUtil::overlap(table_ids, left_tables) && - ObOptimizerUtil::overlap(table_ids, right_tables)) { - has_equal = true; + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null condition", K(ret)); + } else if (cond->has_flag(CNT_SUB_QUERY)) { + has_subquery = true; } - } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObRawExprUtils::extract_table_ids(cond, table_ids))) { + LOG_WARN("failed to extract table ids", K(ret)); + } else if (table_ids.empty()) { + //do nothing + } else if (cond->has_flag(IS_JOIN_COND)) { + ObRawExpr *left_param = NULL; + ObRawExpr *right_param = NULL; + left_table_ids.reuse(); + right_table_ids.reuse(); + if (cond->get_param_count() != 2 || + OB_ISNULL(left_param = cond->get_param_expr(0)) || + OB_ISNULL(right_param = cond->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null param", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::extract_table_ids(left_param, left_table_ids))) { + LOG_WARN("failed to extract table ids", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::extract_table_ids(right_param, right_table_ids))) { + LOG_WARN("failed to extract table ids", K(ret)); + } else if ((ObOptimizerUtil::is_subset(left_table_ids, left_tables) && + ObOptimizerUtil::is_subset(right_table_ids, right_tables)) || + (ObOptimizerUtil::is_subset(left_table_ids, right_tables) && + ObOptimizerUtil::is_subset(right_table_ids, left_tables))) { + has_equal = true; + } + } + } return ret; } diff --git a/src/sql/rewrite/ob_transform_full_outer_join.h b/src/sql/rewrite/ob_transform_full_outer_join.h index bdf6a886f0..38cd8ebfa5 100644 --- a/src/sql/rewrite/ob_transform_full_outer_join.h +++ b/src/sql/rewrite/ob_transform_full_outer_join.h @@ -35,7 +35,12 @@ private: int transform_full_outer_join(ObDMLStmt*& stmt, bool& trans_happened); - int check_join_condition(ObDMLStmt* stmt, JoinedTable* table, bool& has_equal); + int check_full_nl_valid(ObDMLStmt &stmt, TableItem* table_item, bool &is_valid); + + int check_join_condition(ObDMLStmt *stmt, + JoinedTable *table, + bool &has_equal, + bool &has_subquery); int recursively_eliminate_full_join(ObDMLStmt* stmt, TableItem*& table_item, bool& trans_happened); diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index 8590ea15ae..3c08ace789 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -250,10 +250,20 @@ int ObTransformPreProcess::transform_for_grouping_sets_and_multi_rollup(ObDMLStm ObSelectStmt* view_stmt = NULL; ObSelectStmt* transform_stmt = NULL; ObSelectStmt* set_view_stmt = NULL; + bool is_correlated = false; + int32_t stmt_level = select_stmt->get_current_level(); // step 1, creating spj stmt if (OB_FAIL(ObTransformUtils::create_simple_view(ctx_, select_stmt, view_stmt))) { LOG_WARN("failed to create spj view.", K(ret)); // step 2, creating temp table + } else if (stmt_level > 0 && + OB_FAIL(ObTransformUtils::is_correlated_subquery(view_stmt, + stmt_level-1, + is_correlated))) { + LOG_WARN("failed to check is correlated subquery", K(ret)); + } else if (is_correlated) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("correlated temp table is not support now!", K(ret)); } else if (OB_FAIL(add_generated_table_as_temp_table(ctx_, select_stmt))) { LOG_WARN("failed to add generated table as temp table", K(ret)); // setp 3, creating set stmt diff --git a/src/sql/rewrite/ob_transform_set_op.cpp b/src/sql/rewrite/ob_transform_set_op.cpp index 49c1d6d140..765ca518ef 100644 --- a/src/sql/rewrite/ob_transform_set_op.cpp +++ b/src/sql/rewrite/ob_transform_set_op.cpp @@ -366,23 +366,62 @@ int ObTransformSetOp::is_calc_found_rows_for_union( } int ObTransformSetOp::recursive_adjust_order_by(ObSelectStmt* stmt, ObRawExpr* cur_expr, ObRawExpr*& find_expr) + { + int ret = OB_SUCCESS; + if (OB_ISNULL(stmt) || OB_ISNULL(cur_expr)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument, expr is NULL", K(ret)); + } else if (cur_expr->is_set_op_expr()) { + ret = replace_select_expr_for_set_op(stmt, cur_expr, find_expr); + } else { + ObRawExpr *new_expr = NULL; + ObRawExprFactory *expr_factory = NULL; + if (OB_ISNULL(expr_factory = ctx_->expr_factory_) || + OB_ISNULL(ctx_->session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("params have null", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::copy_expr( + *expr_factory, cur_expr, new_expr, COPY_REF_DEFAULT))) { + LOG_WARN("failed to copy expr", K(ret)); + } else if (OB_FAIL(replace_select_expr_for_set_op( + stmt, new_expr, find_expr))) { + LOG_WARN("failed to replace expr", K(ret)); + } else if (OB_FAIL(find_expr->formalize(ctx_->session_info_))) { + LOG_WARN("failed to formalize expr", K(ret)); + } else if (OB_FAIL(find_expr->pull_relation_id_and_levels(stmt->get_current_level()))) { + LOG_WARN("failed to pull relation id and levels", K(ret)); + } + } + return ret; +} + +int ObTransformSetOp::replace_select_expr_for_set_op(ObSelectStmt *stmt, + ObRawExpr *cur_expr, + ObRawExpr *&find_expr) { int ret = OB_SUCCESS; - ObRawExpr* set_expr = NULL; - int64_t idx = -1; if (OB_ISNULL(stmt) || OB_ISNULL(cur_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument, expr is NULL", K(ret)); - } else if (OB_ISNULL(set_expr = ObTransformUtils::get_expr_in_cast(cur_expr)) || - OB_UNLIKELY(!set_expr->is_set_op_expr())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected set expr", K(ret), K(set_expr)); - } else if (OB_FALSE_IT(idx = static_cast(set_expr)->get_idx())) { - } else if (idx < 0 || idx >= stmt->get_select_item_size()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("union expr param count is wrong", K(ret), K(idx), K(stmt->get_select_item_size())); - } else { - find_expr = stmt->get_select_item(idx).expr_; + } else if (cur_expr->is_set_op_expr()) { + int64_t idx = static_cast(cur_expr)->get_idx(); + if (idx < 0 || idx >= stmt->get_select_item_size()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("union expr param count is wrong", K(ret), K(idx), K(stmt->get_select_item_size())); + } else { + find_expr = stmt->get_select_item(idx).expr_; + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < cur_expr->get_param_count(); ++i) { + ObRawExpr *&expr = cur_expr->get_param_expr(i); + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null expr", K(ret)); + } else if (OB_FAIL(SMART_CALL(replace_select_expr_for_set_op(stmt, expr, expr)))) { + LOG_WARN("failed to replace select expr", K(ret)); + } + } + find_expr = cur_expr; } return ret; } diff --git a/src/sql/rewrite/ob_transform_set_op.h b/src/sql/rewrite/ob_transform_set_op.h index 0b045db7d4..f29943f4e3 100644 --- a/src/sql/rewrite/ob_transform_set_op.h +++ b/src/sql/rewrite/ob_transform_set_op.h @@ -49,6 +49,9 @@ private: int add_limit_order_for_union(const common::ObIArray& parent_stmts, ObSelectStmt*& stmt); int check_can_pre_push(ObSelectStmt* stmt, ObSelectStmt* upper_stmt, bool& can_push); + int replace_select_expr_for_set_op(ObSelectStmt *stmt, + ObRawExpr *cur_expr, + ObRawExpr *&find_expr); private: DISALLOW_COPY_AND_ASSIGN(ObTransformSetOp); }; diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index 6c363f19bd..3642f80493 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -61,6 +61,43 @@ int ObTransformUtils::is_correlated_expr(const ObRawExpr* expr, int32_t correlat return ret; } +int ObTransformUtils::is_correlated_subquery(ObSelectStmt* subquery, + int32_t correlated_level, + bool &is_correlated) +{ + int ret = OB_SUCCESS; + is_correlated = false; + ObArray relation_exprs; + ObArray child_stmts; + if (OB_ISNULL(subquery)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null stmt", K(ret)); + } else if (OB_FAIL(subquery->get_relation_exprs(relation_exprs))) { + LOG_WARN("get relation exprs failed", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < relation_exprs.count(); ++i) { + if (OB_FAIL(is_correlated_expr(relation_exprs.at(i), + correlated_level, + is_correlated))) { + LOG_WARN("failed to check is correlated expr", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(subquery->get_child_stmts(child_stmts))) { + LOG_WARN("get from subquery stmts failed", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < child_stmts.count(); ++i) { + if (OB_FAIL(SMART_CALL(is_correlated_subquery(child_stmts.at(i), + correlated_level, + is_correlated)))) { + LOG_WARN("failed to check is correlated subquery", K(ret)); + } + } + } + return ret; +} + + int ObTransformUtils::is_direct_correlated_expr( const ObRawExpr* expr, int32_t correlated_level, bool& is_direct_correlated) { diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index e1644c8c91..5bc4b2ef4d 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -83,6 +83,10 @@ private: public: static int is_correlated_expr(const ObRawExpr* expr, int32_t correlated_level, bool& is_correlated); + static int is_correlated_subquery(ObSelectStmt* subquery, + int32_t correlated_level, + bool &is_correlated); + static int is_direct_correlated_expr(const ObRawExpr* expr, int32_t correlated_level, bool& is_direct_correlated); static int has_current_level_column(const ObRawExpr* expr, int32_t curlevel, bool& has); diff --git a/unittest/sql/optimizer/test_optimizer_default_stat.result b/unittest/sql/optimizer/test_optimizer_default_stat.result index 3f53f967ed..777c382661 100644 --- a/unittest/sql/optimizer/test_optimizer_default_stat.result +++ b/unittest/sql/optimizer/test_optimizer_default_stat.result @@ -2221,25 +2221,25 @@ Outputs & filters: SQL: select * from t1 left join t2 t on 1=1 where false; -================================================================= -|ID|OPERATOR |NAME |EST. ROWS |COST | ------------------------------------------------------------------ -|0 |NESTED-LOOP OUTER JOIN | |150000000000|126539013545| -|1 | PX COORDINATOR | |500000 |356592 | -|2 | EXCHANGE OUT DISTR |:EX10000|500000 |309262 | -|3 | PX PARTITION ITERATOR | |500000 |309262 | -|4 | TABLE SCAN |t1 |500000 |309262 | -|5 | MATERIAL | |300000 |608147 | -|6 | PX COORDINATOR | |300000 |277391 | -|7 | EXCHANGE OUT DISTR |:EX20000|300000 |192197 | -|8 | PX PARTITION ITERATOR| |300000 |192197 | -|9 | TABLE SCAN |t |300000 |192197 | -================================================================= +======================================================================== +|ID|OPERATOR |NAME |EST. ROWS |COST | +------------------------------------------------------------------------ +|0 |NESTED-LOOP OUTER JOIN CARTESIAN| |150000000000|113980406167| +|1 | PX COORDINATOR | |500000 |356592 | +|2 | EXCHANGE OUT DISTR |:EX10000|500000 |309262 | +|3 | PX PARTITION ITERATOR | |500000 |309262 | +|4 | TABLE SCAN |t1 |500000 |309262 | +|5 | MATERIAL | |300000 |633265 | +|6 | PX COORDINATOR | |300000 |302508 | +|7 | EXCHANGE OUT DISTR |:EX20000|300000 |217314 | +|8 | PX PARTITION ITERATOR | |300000 |217314 | +|9 | TABLE SCAN |t |300000 |217314 | +======================================================================== Outputs & filters: ------------------------------------- 0 - output([t1.c1], [t1.c2], [t.c1], [t.c2], [t.c3]), filter(nil), startup_filter([0]), - conds([1]), nl_params_(nil), batch_join=false + conds(nil), nl_params_(nil), batch_join=false 1 - output([t1.c1], [t1.c2]), filter(nil) 2 - output([t1.c1], [t1.c2]), filter(nil), dop=1 3 - output([t1.c1], [t1.c2]), filter(nil), @@ -2253,7 +2253,7 @@ Outputs & filters: 7 - output([t.c1], [t.c2], [t.c3]), filter(nil), dop=1 8 - output([t.c1], [t.c2], [t.c3]), filter(nil), force partition granule, asc. - 9 - output([t.c1], [t.c2], [t.c3]), filter(nil), startup_filter([0]), + 9 - output([t.c1], [t.c2], [t.c3]), filter(nil), startup_filter([1], [0]), access([t.c1], [t.c2], [t.c3]), partitions(p[0-2]), is_index_back=false, range_key([t.c1]), range(MIN ; MAX)always true diff --git a/unittest/sql/optimizer/test_optimizer_select.result b/unittest/sql/optimizer/test_optimizer_select.result index fd63be5edf..e665146618 100644 --- a/unittest/sql/optimizer/test_optimizer_select.result +++ b/unittest/sql/optimizer/test_optimizer_select.result @@ -2283,25 +2283,25 @@ Outputs & filters: SQL: select * from t1 left join t2 t on 1=1 where false; -======================================================== -|ID|OPERATOR |NAME |EST. ROWS|COST | --------------------------------------------------------- -|0 |NESTED-LOOP OUTER JOIN | |150000 |127547| -|1 | PX COORDINATOR | |500 |389 | -|2 | EXCHANGE OUT DISTR |:EX10000|500 |342 | -|3 | PX PARTITION ITERATOR | |500 |342 | -|4 | TABLE SCAN |t1 |500 |342 | -|5 | MATERIAL | |300 |621 | -|6 | PX COORDINATOR | |300 |290 | -|7 | EXCHANGE OUT DISTR |:EX20000|300 |205 | -|8 | PX PARTITION ITERATOR| |300 |205 | -|9 | TABLE SCAN |t |300 |205 | -======================================================== +=============================================================== +|ID|OPERATOR |NAME |EST. ROWS|COST | +--------------------------------------------------------------- +|0 |NESTED-LOOP OUTER JOIN CARTESIAN| |150000 |115014| +|1 | PX COORDINATOR | |500 |389 | +|2 | EXCHANGE OUT DISTR |:EX10000|500 |342 | +|3 | PX PARTITION ITERATOR | |500 |342 | +|4 | TABLE SCAN |t1 |500 |342 | +|5 | MATERIAL | |300 |646 | +|6 | PX COORDINATOR | |300 |315 | +|7 | EXCHANGE OUT DISTR |:EX20000|300 |230 | +|8 | PX PARTITION ITERATOR | |300 |230 | +|9 | TABLE SCAN |t |300 |230 | +=============================================================== Outputs & filters: ------------------------------------- 0 - output([t1.c1], [t1.c2], [t.c1], [t.c2], [t.c3]), filter(nil), startup_filter([0]), - conds([1]), nl_params_(nil), batch_join=false + conds(nil), nl_params_(nil), batch_join=false 1 - output([t1.c1], [t1.c2]), filter(nil) 2 - output([t1.c1], [t1.c2]), filter(nil), dop=1 3 - output([t1.c1], [t1.c2]), filter(nil), @@ -2315,7 +2315,7 @@ Outputs & filters: 7 - output([t.c1], [t.c2], [t.c3]), filter(nil), dop=1 8 - output([t.c1], [t.c2], [t.c3]), filter(nil), force partition granule, asc. - 9 - output([t.c1], [t.c2], [t.c3]), filter(nil), startup_filter([0]), + 9 - output([t.c1], [t.c2], [t.c3]), filter(nil), startup_filter([1], [0]), access([t.c1], [t.c2], [t.c3]), partitions(p[0-2]), is_index_back=false, range_key([t.c1]), range(MIN ; MAX)always true @@ -16287,31 +16287,28 @@ Outputs & filters: SQL: select * from t1 left join t2 on (1 = 0 or t1.c1 = t2.c1) left join t3 on (1=2 and t2.c1 = t3.c1); -============================================================== -|ID|OPERATOR |NAME |EST. ROWS|COST | --------------------------------------------------------------- -|0 |NESTED-LOOP OUTER JOIN | |500 |35573| -|1 | PX COORDINATOR | |500 |1725 | -|2 | EXCHANGE OUT DISTR |:EX10001|500 |1536 | -|3 | MERGE OUTER JOIN | |500 |1536 | -|4 | EXCHANGE IN MERGE SORT DISTR| |500 |389 | -|5 | EXCHANGE OUT DISTR (PKEY) |:EX10000|500 |342 | -|6 | PX PARTITION ITERATOR | |500 |342 | -|7 | TABLE SCAN |t1 |500 |342 | -|8 | SORT | |300 |859 | -|9 | PX PARTITION ITERATOR | |300 |205 | -|10| TABLE SCAN |t2 |300 |205 | -|11| MATERIAL | |200 |426 | -|12| PX COORDINATOR | |200 |205 | -|13| EXCHANGE OUT DISTR |:EX20000|200 |149 | -|14| PX PARTITION ITERATOR | |200 |149 | -|15| TABLE SCAN |t3 |200 |149 | -============================================================== +============================================================= +|ID|OPERATOR |NAME |EST. ROWS|COST| +------------------------------------------------------------- +|0 |NESTED-LOOP OUTER JOIN CARTESIAN| |500 |1825| +|1 | PX COORDINATOR | |500 |1725| +|2 | EXCHANGE OUT DISTR |:EX10001|500 |1536| +|3 | MERGE OUTER JOIN | |500 |1536| +|4 | EXCHANGE IN MERGE SORT DISTR| |500 |389 | +|5 | EXCHANGE OUT DISTR (PKEY) |:EX10000|500 |342 | +|6 | PX PARTITION ITERATOR | |500 |342 | +|7 | TABLE SCAN |t1 |500 |342 | +|8 | SORT | |300 |859 | +|9 | PX PARTITION ITERATOR | |300 |205 | +|10| TABLE SCAN |t2 |300 |205 | +|11| MATERIAL | |0 |101 | +|12| TABLE SCAN |t3 |0 |101 | +============================================================= Outputs & filters: ------------------------------------- 0 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2], [t2.c3], [t3.c1], [t3.c2], [t3.c3]), filter(nil), - conds([0]), nl_params_(nil), batch_join=false + conds(nil), nl_params_(nil), batch_join=false 1 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2], [t2.c3]), filter(nil) 2 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2], [t2.c3]), filter(nil), dop=1 3 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2], [t2.c3]), filter(nil), @@ -16332,14 +16329,10 @@ Outputs & filters: is_index_back=false, range_key([t2.c1]), range(MIN ; MAX)always true 11 - output([t3.c1], [t3.c2], [t3.c3]), filter(nil) - 12 - output([t3.c1], [t3.c2], [t3.c3]), filter(nil) - 13 - output([t3.c1], [t3.c2], [t3.c3]), filter(nil), dop=1 - 14 - output([t3.c1], [t3.c2], [t3.c3]), filter(nil), - force partition granule, asc. - 15 - output([t3.c1], [t3.c2], [t3.c3]), filter(nil), - access([t3.c1], [t3.c2], [t3.c3]), partitions(p[0-1]), + 12 - output([t3.c1], [t3.c2], [t3.c3]), filter(nil), startup_filter([0]), + access([t3.c1], [t3.c2], [t3.c3]), partitions(p0), is_index_back=false, - range_key([t3.c1]), range(MIN ; MAX)always true + range_key([t3.c1]), range(MAX ; MIN)always false *************** Case 472(end) **************