Commit fa29f18f authored by Igor Babaev's avatar Igor Babaev

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.
parent 8a09adb3
...@@ -5313,4 +5313,83 @@ a b c d ...@@ -5313,4 +5313,83 @@ a b c d
SET SESSION join_cache_level = DEFAULT; SET SESSION join_cache_level = DEFAULT;
SET optimizer_switch=@tmp_optimizer_switch; SET optimizer_switch=@tmp_optimizer_switch;
DROP TABLE t1,t2,t3; 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; set @@optimizer_switch=@save_optimizer_switch;
...@@ -3361,5 +3361,68 @@ SET optimizer_switch=@tmp_optimizer_switch; ...@@ -3361,5 +3361,68 @@ SET optimizer_switch=@tmp_optimizer_switch;
DROP TABLE t1,t2,t3; 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 # this must be the last command in the file
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -4138,6 +4138,16 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, ...@@ -4138,6 +4138,16 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
{ {
/* Looks like we'll be using join buffer */ /* Looks like we'll be using join buffer */
first_table= join->const_tables; 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; break;
} }
} }
......
...@@ -1524,22 +1524,7 @@ JOIN::optimize() ...@@ -1524,22 +1524,7 @@ JOIN::optimize()
} }
} }
/* need_tmp= test_if_need_tmp_table();
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));
/* /*
If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the table If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the table
......
...@@ -1318,6 +1318,25 @@ class JOIN :public Sql_alloc ...@@ -1318,6 +1318,25 @@ class JOIN :public Sql_alloc
return test(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && return test(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
max_allowed_join_cache_level > 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); bool choose_subquery_plan(table_map join_tables);
void get_partial_cost_and_fanout(int end_tab_idx, void get_partial_cost_and_fanout(int end_tab_idx,
table_map filter_map, table_map filter_map,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment