diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index ef5c0a66130..6dbaa5a93a0 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5264,4 +5264,53 @@ a SET SESSION join_cache_level = DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #900469: semijoin + BNLH + ORDER BY +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (8,10); +CREATE TABLE t2 (c int, d int); +INSERT INTO t2 VALUES (8,10); +INSERT INTO t2 VALUES (9,11); +CREATE TABLE t3 (c int, d int); +INSERT INTO t3 VALUES (8,10); +INSERT INTO t3 VALUES (9,11); +SET @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin_with_cache=on'; +SET join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +a b c d +8 10 8 10 +8 10 9 11 +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 hash_ALL NULL #hash#$hj 5 const 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); +a b c d +8 10 8 10 +8 10 9 11 +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 hash_ALL NULL #hash#$hj 5 const 2 Using where; Start temporary; End temporary; Using join buffer (flat, BNLH join) +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +a b c d +8 10 8 10 +8 10 9 11 +SET SESSION join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index ac92ff1631b..ef64e8caea1 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3323,5 +3323,43 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #900469: semijoin + BNLH + ORDER BY +--echo # + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (8,10); + +CREATE TABLE t2 (c int, d int); +INSERT INTO t2 VALUES (8,10); +INSERT INTO t2 VALUES (9,11); + +CREATE TABLE t3 (c int, d int); +INSERT INTO t3 VALUES (8,10); +INSERT INTO t3 VALUES (9,11); + +SET @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin_with_cache=on'; + +SET join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; + +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c); + +SET join_cache_level=3; +EXPLAIN +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; +SELECT * FROM t1,t2 WHERE b IN (SELECT d FROM t3 WHERE c <= t2.c) ORDER BY a,d; + +SET SESSION join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ba7ae875be9..03ba5bb7790 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1448,7 +1448,7 @@ JOIN::optimize() order=0; // Can't use sort on head table if using join buffering - if (full_join) + if (full_join || hash_join) { TABLE *stable= (sort_by_table == (TABLE *) 1 ? join_tab[const_tables].table : sort_by_table); @@ -7036,6 +7036,7 @@ get_best_combination(JOIN *join) DBUG_RETURN(TRUE); join->full_join=0; + join->hash_join= FALSE; used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read @@ -7125,6 +7126,11 @@ get_best_combination(JOIN *join) } else if (create_ref_for_key(join, j, keyuse, used_tables)) DBUG_RETURN(TRUE); // Something went wrong + + if ((j->type == JT_REF || j->type == JT_EQ_REF) && + is_hash_join_key_no(j->ref.key)) + join->hash_join= TRUE; + loop_end: /* Save records_read in JOIN_TAB so that select_describe()/etc don't have diff --git a/sql/sql_select.h b/sql/sql_select.h index ffe3985c3c3..e24cab714fd 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -912,6 +912,7 @@ public: */ bool sort_and_group; bool first_record,full_join, no_field_update; + bool hash_join; bool do_send_rows; /** TRUE when we want to resume nested loop iterations when