diff options
author | Igor Babaev <igor@askmonty.org> | 2011-12-11 12:56:06 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2011-12-11 12:56:06 -0800 |
commit | fa29f18ffbc8c60c4aec3c74b4013056c7c32169 (patch) | |
tree | e0fde4651e4bb900437891ba2f7ab5c635c21b45 | |
parent | 8a09adb3eaf036b652b11afea7d9d86a978fa566 (diff) | |
download | mariadb-git-fa29f18ffbc8c60c4aec3c74b4013056c7c32169.tar.gz |
Fixed LP bug #901478.
If the duplicate elimination strategy is used for a semi-join and potentially
one of the block-based join algorithms can be employed to join the inner
tables of the semi-join then sorting of the head (first non-constant) table
for a query with ORDER BY / GROUP BY cannot be used.
-rw-r--r-- | mysql-test/r/join_cache.result | 79 | ||||
-rw-r--r-- | mysql-test/t/join_cache.test | 63 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 10 | ||||
-rw-r--r-- | sql/sql_select.cc | 17 | ||||
-rw-r--r-- | sql/sql_select.h | 19 |
5 files changed, 172 insertions, 16 deletions
diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 6dbaa5a93a0..f2fda746e5e 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5313,4 +5313,83 @@ a b c d SET SESSION join_cache_level = DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #901478: semijoin + ORDER BY + join_cache_level=4|6 +# +CREATE TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('x'); +CREATE TABLE t2 (a int, b int, c int, KEY(a), KEY(b), KEY(c)); +INSERT INTO t2 VALUES +(9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +CREATE TABLE t3 (a CHAR(1)); +INSERT INTO t3 VALUES ('x'); +CREATE TABLE t4 (a int, b int, c int, KEY(b), KEY(c)); +INSERT INTO t4 VALUES +(9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +INSERT INTO t4 VALUES +(19,11,10), (17,12,18), (12,13,15), (14,12,19), +(18,13,18), (13,14,11), (15,15,14); +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='firstmatch=off'; +SET @@optimizer_switch='mrr=off'; +SET @@optimizer_switch='semijoin_with_cache=off'; +set join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 Using filesort +1 PRIMARY t3 system NULL NULL NULL NULL 1 +1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where +1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +a a b c +x 4 2 9 +x 5 5 4 +set join_cache_level=4; +EXPLAIN +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +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 t3 system NULL NULL NULL NULL 1 +1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where +1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +a a b c +x 4 2 9 +x 5 5 4 +SET @@optimizer_switch='semijoin_with_cache=on'; +set join_cache_level=6; +EXPLAIN +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +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 t3 system NULL NULL NULL NULL 1 +1 PRIMARY t2 range a,c a 5 NULL 1 Using index condition; Using where +1 PRIMARY t4 ref c c 5 test.t2.c 2 Using where; Start temporary; End temporary +SELECT * FROM t1,t2 +WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND +t2.a BETWEEN 4 and 5 +ORDER BY t2.b; +a a b c +x 4 2 9 +x 5 5 4 +SET join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3,t4; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index ef64e8caea1..5a48f7653e4 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3361,5 +3361,68 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #901478: semijoin + ORDER BY + join_cache_level=4|6 +--echo # + +CREATE TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('x'); +CREATE TABLE t2 (a int, b int, c int, KEY(a), KEY(b), KEY(c)); +INSERT INTO t2 VALUES + (9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +CREATE TABLE t3 (a CHAR(1)); +INSERT INTO t3 VALUES ('x'); +CREATE TABLE t4 (a int, b int, c int, KEY(b), KEY(c)); +INSERT INTO t4 VALUES + (9,1,0), (7,2,8), (2,3,5), (4,2,9), (8,3,8), (3,4,1), (5,5,4); +INSERT INTO t4 VALUES + (19,11,10), (17,12,18), (12,13,15), (14,12,19), + (18,13,18), (13,14,11), (15,15,14); + +SET @tmp_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch='semijoin=on'; +SET @@optimizer_switch='firstmatch=off'; +SET @@optimizer_switch='mrr=off'; +SET @@optimizer_switch='semijoin_with_cache=off'; + +set join_cache_level=1; +EXPLAIN +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; + +set join_cache_level=4; +EXPLAIN +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; + +SET @@optimizer_switch='semijoin_with_cache=on'; +set join_cache_level=6; +EXPLAIN +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; +SELECT * FROM t1,t2 + WHERE t2.c IN (SELECT c FROM t3,t4 WHERE t4.a < 10) AND + t2.a BETWEEN 4 and 5 + ORDER BY t2.b; + +SET join_cache_level = DEFAULT; +SET optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3,t4; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 0819667e068..217966eb296 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4138,6 +4138,16 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, { /* Looks like we'll be using join buffer */ first_table= join->const_tables; + /* + Make sure that possible sorting of rows from the head table + is not to be employed. + */ + if (join->get_sort_by_join_tab()) + { + join->simple_order= 0; + join->simple_group= 0; + join->need_tmp= join->test_if_need_tmp_table(); + } break; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7a86557901f..a4f3a1ee467 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1524,22 +1524,7 @@ JOIN::optimize() } } - /* - Check if we need to create a temporary table. - This has to be done if all tables are not already read (const tables) - and one of the following conditions holds: - - We are using DISTINCT (simple distinct's are already optimized away) - - We are using an ORDER BY or GROUP BY on fields not in the first table - - We are using different ORDER BY and GROUP BY orders - - The user wants us to buffer the result. - When the WITH ROLLUP modifier is present, we cannot skip temporary table - creation for the DISTINCT clause just because there are only const tables. - */ - need_tmp= ((const_tables != table_count && - ((select_distinct || !simple_order || !simple_group) || - (group_list && order) || - test(select_options & OPTION_BUFFER_RESULT))) || - (rollup.state != ROLLUP::STATE_NONE && select_distinct)); + need_tmp= test_if_need_tmp_table(); /* If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the table diff --git a/sql/sql_select.h b/sql/sql_select.h index e24cab714fd..5a8dc846c92 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1318,6 +1318,25 @@ public: return test(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT; } + /* + Check if we need to create a temporary table. + This has to be done if all tables are not already read (const tables) + and one of the following conditions holds: + - We are using DISTINCT (simple distinct's are already optimized away) + - We are using an ORDER BY or GROUP BY on fields not in the first table + - We are using different ORDER BY and GROUP BY orders + - The user wants us to buffer the result. + When the WITH ROLLUP modifier is present, we cannot skip temporary table + creation for the DISTINCT clause just because there are only const tables. + */ + bool test_if_need_tmp_table() + { + return ((const_tables != table_count && + ((select_distinct || !simple_order || !simple_group) || + (group_list && order) || + test(select_options & OPTION_BUFFER_RESULT))) || + (rollup.state != ROLLUP::STATE_NONE && select_distinct)); + } bool choose_subquery_plan(table_map join_tables); void get_partial_cost_and_fanout(int end_tab_idx, table_map filter_map, |