mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
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.
This commit is contained in:
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user