diff options
-rw-r--r-- | mysql-test/r/join_outer.result | 59 | ||||
-rw-r--r-- | mysql-test/t/join_outer.test | 44 | ||||
-rw-r--r-- | sql/sql_select.cc | 28 | ||||
-rw-r--r-- | sql/sql_select.h | 4 |
4 files changed, 124 insertions, 11 deletions
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 8c9c121c9be..f9fb545bd0e 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1449,4 +1449,63 @@ group by t2.pk; pk t 2001 3001 drop table t1,t2,t3,t4; +# +# Bug#57024: Poor performance when conjunctive condition over the outer +# table is used in the on condition of an outer join +# +create table t1 (a int); +insert into t1 values (NULL), (NULL), (NULL), (NULL); +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 values (4), (2), (1), (3); +create table t2 like t1; +insert into t2 select if(t1.a is null, 10, t1.a) from t1; +create table t3 (a int, b int, index idx(a)); +insert into t3 values (1, 100), (3, 301), (4, 402), (1, 102), (1, 101); +analyze table t1,t2,t3; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +test.t3 analyze status OK +flush status; +select sum(t3.b) from t1 left join t3 on t3.a=t1.a and t1.a is not null; +sum(t3.b) +1006 +show status like "handler_read%"; +Variable_name Value +Handler_read_first 0 +Handler_read_key 4 +Handler_read_next 5 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 1048581 +flush status; +select sum(t3.b) from t2 left join t3 on t3.a=t2.a and t2.a <> 10; +sum(t3.b) +1006 +show status like "handler_read%"; +Variable_name Value +Handler_read_first 0 +Handler_read_key 4 +Handler_read_next 5 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 1048581 +drop table t1,t2,t3; End of 5.1 tests diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index cbc65d66624..6d1ef15337f 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1029,4 +1029,48 @@ select t2.pk, drop table t1,t2,t3,t4; +--echo # +--echo # Bug#57024: Poor performance when conjunctive condition over the outer +--echo # table is used in the on condition of an outer join +--echo # + +create table t1 (a int); +insert into t1 values (NULL), (NULL), (NULL), (NULL); +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 values (4), (2), (1), (3); + +create table t2 like t1; +insert into t2 select if(t1.a is null, 10, t1.a) from t1; + +create table t3 (a int, b int, index idx(a)); +insert into t3 values (1, 100), (3, 301), (4, 402), (1, 102), (1, 101); + +analyze table t1,t2,t3; + +flush status; +select sum(t3.b) from t1 left join t3 on t3.a=t1.a and t1.a is not null; +show status like "handler_read%"; +flush status; +select sum(t3.b) from t2 left join t3 on t3.a=t2.a and t2.a <> 10; +show status like "handler_read%"; + +drop table t1,t2,t3; + --echo End of 5.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8df9b6aff3f..5471b35e250 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6632,6 +6632,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (tmp_cond) { JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab; + Item **sel_cond_ref= tab < first_inner_tab ? + &first_inner_tab->on_precond : + &tab->select_cond; /* First add the guards for match variables of all embedding outer join operations. @@ -6654,14 +6657,14 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) tmp_cond->quick_fix_field(); /* Add the predicate to other pushed down predicates */ DBUG_PRINT("info", ("Item_cond_and")); - cond_tab->select_cond= !cond_tab->select_cond ? tmp_cond : - new Item_cond_and(cond_tab->select_cond, - tmp_cond); + *sel_cond_ref= !(*sel_cond_ref) ? + tmp_cond : + new Item_cond_and(*sel_cond_ref, tmp_cond); DBUG_PRINT("info", ("Item_cond_and 0x%lx", - (ulong)cond_tab->select_cond)); - if (!cond_tab->select_cond) - DBUG_RETURN(1); - cond_tab->select_cond->quick_fix_field(); + (ulong)(*sel_cond_ref))); + if (!(*sel_cond_ref)) + DBUG_RETURN(1); + (*sel_cond_ref)->quick_fix_field(); } } first_inner_tab= first_inner_tab->first_upper; @@ -11646,7 +11649,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return (*join_tab->next_select)(join,join_tab+1,end_of_records); int error; - enum_nested_loop_state rc; + enum_nested_loop_state rc= NESTED_LOOP_OK; READ_RECORD *info= &join_tab->read_record; if (join->resume_nested_loop) @@ -11674,11 +11677,16 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) /* Set first_unmatched for the last inner table of this group */ join_tab->last_inner->first_unmatched= join_tab; + if (join_tab->on_precond && !join_tab->on_precond->val_int()) + rc= NESTED_LOOP_NO_MORE_ROWS; } join->thd->row_count= 0; - error= (*join_tab->read_first_record)(join_tab); - rc= evaluate_join_record(join, join_tab, error); + if (rc != NESTED_LOOP_NO_MORE_ROWS) + { + error= (*join_tab->read_first_record)(join_tab); + rc= evaluate_join_record(join, join_tab, error); + } } while (rc == NESTED_LOOP_OK) diff --git a/sql/sql_select.h b/sql/sql_select.h index fe3cc1af400..b3938fbbbb6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -154,7 +154,9 @@ typedef struct st_join_table { TABLE *table; KEYUSE *keyuse; /**< pointer to first used key */ SQL_SELECT *select; - COND *select_cond; + COND *select_cond; + COND *on_precond; /**< part of on condition to check before + accessing the first inner table */ QUICK_SELECT_I *quick; Item **on_expr_ref; /**< pointer to the associated on expression */ COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */ |