Skip to content
Permalink
Browse files

Fixed bug mdev-7992.

'Not exists' optimization can be used for nested outer joins
only if IS NULL predicate from the WHERE condition is activated.
So we have to check that all guards that wrap this predicate
are in the 'open' state.
This patch supports usage of 'Not exists' optimization for any
outer join, no matter how it's nested in other outer joins.

This patch is also considered as a proper fix for bugs
#49322/#58490 and LP #817360.
  • Loading branch information...
igorbabaev committed Feb 24, 2017
1 parent bdb672f commit ac78927aefa2bd0d869d999839480d69086a9882
Showing with 294 additions and 40 deletions.
  1. +95 −0 mysql-test/r/join_nested.result
  2. +95 −0 mysql-test/r/join_nested_jcl6.result
  3. +70 −1 mysql-test/t/join_nested.test
  4. +34 −39 sql/sql_select.cc
@@ -1870,4 +1870,99 @@ f4
NULL
NULL
DROP TABLE t1,t2,t3,t4,t5;
#
# MDEV-7992: Nested left joins + 'not exists' optimization
#
CREATE TABLE t1(
K1 INT PRIMARY KEY,
Name VARCHAR(15)
);
INSERT INTO t1 VALUES
(1,'T1Row1'), (2,'T1Row2');
CREATE TABLE t2(
K2 INT PRIMARY KEY,
K1r INT,
rowTimestamp DATETIME,
Event VARCHAR(15)
);
INSERT INTO t2 VALUES
(1, 1, '2015-04-13 10:42:11' ,'T1Row1Event1'),
(2, 1, '2015-04-13 10:42:12' ,'T1Row1Event2'),
(3, 1, '2015-04-13 10:42:12' ,'T1Row1Event3');
SELECT t1a.*, t2a.*,
t2i.K2 AS K2B, t2i.K1r AS K1rB,
t2i.rowTimestamp AS rowTimestampB, t2i.Event AS EventB
FROM
t1 t1a JOIN t2 t2a ON t2a.K1r = t1a.K1
LEFT JOIN
( t1 t1i LEFT JOIN t2 t2i ON t2i.K1r = t1i.K1)
ON (t1i.K1 = 1) AND
(((t2i.K1r = t1a.K1 AND t2i.rowTimestamp > t2a.rowTimestamp ) OR
(t2i.rowTimestamp = t2a.rowTimestamp AND t2i.K2 > t2a.K2))
OR (t2i.K2 IS NULL))
WHERE
t2a.K1r = 1 AND t2i.K2 IS NULL;
K1 Name K2 K1r rowTimestamp Event K2B K1rB rowTimestampB EventB
1 T1Row1 3 1 2015-04-13 10:42:12 T1Row1Event3 NULL NULL NULL NULL
EXPLAIN EXTENDED SELECT t1a.*, t2a.*,
t2i.K2 AS K2B, t2i.K1r AS K1rB,
t2i.rowTimestamp AS rowTimestampB, t2i.Event AS EventB
FROM
t1 t1a JOIN t2 t2a ON t2a.K1r = t1a.K1
LEFT JOIN
( t1 t1i LEFT JOIN t2 t2i ON t2i.K1r = t1i.K1)
ON (t1i.K1 = 1) AND
(((t2i.K1r = t1a.K1 AND t2i.rowTimestamp > t2a.rowTimestamp ) OR
(t2i.rowTimestamp = t2a.rowTimestamp AND t2i.K2 > t2a.K2))
OR (t2i.K2 IS NULL))
WHERE
t2a.K1r = 1 AND t2i.K2 IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1a const PRIMARY PRIMARY 4 const 1 100.00
1 SIMPLE t2a ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1i const PRIMARY PRIMARY 4 const 1 100.00 Using index
1 SIMPLE t2i ALL NULL NULL NULL NULL 3 100.00 Using where; Not exists
Warnings:
Note 1003 select 1 AS `K1`,'T1Row1' AS `Name`,`test`.`t2a`.`K2` AS `K2`,`test`.`t2a`.`K1r` AS `K1r`,`test`.`t2a`.`rowTimestamp` AS `rowTimestamp`,`test`.`t2a`.`Event` AS `Event`,`test`.`t2i`.`K2` AS `K2B`,`test`.`t2i`.`K1r` AS `K1rB`,`test`.`t2i`.`rowTimestamp` AS `rowTimestampB`,`test`.`t2i`.`Event` AS `EventB` from `test`.`t1` `t1a` join `test`.`t2` `t2a` left join (`test`.`t1` `t1i` left join `test`.`t2` `t2i` on((`test`.`t2i`.`K1r` = 1))) on(((`test`.`t1i`.`K1` = 1) and (((`test`.`t2i`.`K1r` = 1) and (`test`.`t2i`.`rowTimestamp` > `test`.`t2a`.`rowTimestamp`)) or ((`test`.`t2i`.`rowTimestamp` = `test`.`t2a`.`rowTimestamp`) and (`test`.`t2i`.`K2` > `test`.`t2a`.`K2`)) or isnull(`test`.`t2i`.`K2`)))) where ((`test`.`t2a`.`K1r` = 1) and isnull(`test`.`t2i`.`K2`))
CREATE VIEW v1 AS
SELECT t2i.*
FROM t1 as t1i LEFT JOIN t2 as t2i ON t2i.K1r = t1i.K1
WHERE t1i.K1 = 1 ;
SELECT
t1a.*, t2a.*, t2b.K2 as K2B, t2b.K1r as K1rB,
t2b.rowTimestamp as rowTimestampB, t2b.Event as EventB
FROM
t1 as t1a JOIN t2 as t2a ON t2a.K1r = t1a.K1
LEFT JOIN
v1 as t2b
ON ((t2b.K1r = t1a.K1 AND t2b.rowTimestamp > t2a.rowTimestamp) OR
(t2b.rowTimestamp = t2a.rowTimestamp AND t2b.K2 > t2a.K2))
OR (t2b.K2 IS NULL)
WHERE
t1a.K1 = 1 AND
t2b.K2 IS NULL;
K1 Name K2 K1r rowTimestamp Event K2B K1rB rowTimestampB EventB
1 T1Row1 3 1 2015-04-13 10:42:12 T1Row1Event3 NULL NULL NULL NULL
EXPLAIN EXTENDED SELECT
t1a.*, t2a.*, t2b.K2 as K2B, t2b.K1r as K1rB,
t2b.rowTimestamp as rowTimestampB, t2b.Event as EventB
FROM
t1 as t1a JOIN t2 as t2a ON t2a.K1r = t1a.K1
LEFT JOIN
v1 as t2b
ON ((t2b.K1r = t1a.K1 AND t2b.rowTimestamp > t2a.rowTimestamp) OR
(t2b.rowTimestamp = t2a.rowTimestamp AND t2b.K2 > t2a.K2))
OR (t2b.K2 IS NULL)
WHERE
t1a.K1 = 1 AND
t2b.K2 IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1a const PRIMARY PRIMARY 4 const 1 100.00
1 SIMPLE t2a ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1i const PRIMARY PRIMARY 4 const 1 100.00 Using index
1 SIMPLE t2i ALL NULL NULL NULL NULL 3 100.00 Using where; Not exists
Warnings:
Note 1003 select 1 AS `K1`,'T1Row1' AS `Name`,`t2a`.`K2` AS `K2`,`t2a`.`K1r` AS `K1r`,`t2a`.`rowTimestamp` AS `rowTimestamp`,`t2a`.`Event` AS `Event`,`test`.`t2i`.`K2` AS `K2B`,`test`.`t2i`.`K1r` AS `K1rB`,`test`.`t2i`.`rowTimestamp` AS `rowTimestampB`,`test`.`t2i`.`Event` AS `EventB` from `test`.`t1` `t1a` join `test`.`t2` `t2a` left join (`test`.`t1` `t1i` left join `test`.`t2` `t2i` on((`test`.`t2i`.`K1r` = 1))) on(((`test`.`t1i`.`K1` = 1) and (((`test`.`t2i`.`K1r` = 1) and (`test`.`t2i`.`rowTimestamp` > `t2a`.`rowTimestamp`)) or ((`test`.`t2i`.`rowTimestamp` = `t2a`.`rowTimestamp`) and (`test`.`t2i`.`K2` > `t2a`.`K2`)) or isnull(`test`.`t2i`.`K2`)))) where ((`t2a`.`K1r` = 1) and isnull(`test`.`t2i`.`K2`))
DROP VIEW v1;
DROP TABLE t1,t2;
set optimizer_search_depth= @tmp_mdev621;
@@ -1881,6 +1881,101 @@ f4
NULL
NULL
DROP TABLE t1,t2,t3,t4,t5;
#
# MDEV-7992: Nested left joins + 'not exists' optimization
#
CREATE TABLE t1(
K1 INT PRIMARY KEY,
Name VARCHAR(15)
);
INSERT INTO t1 VALUES
(1,'T1Row1'), (2,'T1Row2');
CREATE TABLE t2(
K2 INT PRIMARY KEY,
K1r INT,
rowTimestamp DATETIME,
Event VARCHAR(15)
);
INSERT INTO t2 VALUES
(1, 1, '2015-04-13 10:42:11' ,'T1Row1Event1'),
(2, 1, '2015-04-13 10:42:12' ,'T1Row1Event2'),
(3, 1, '2015-04-13 10:42:12' ,'T1Row1Event3');
SELECT t1a.*, t2a.*,
t2i.K2 AS K2B, t2i.K1r AS K1rB,
t2i.rowTimestamp AS rowTimestampB, t2i.Event AS EventB
FROM
t1 t1a JOIN t2 t2a ON t2a.K1r = t1a.K1
LEFT JOIN
( t1 t1i LEFT JOIN t2 t2i ON t2i.K1r = t1i.K1)
ON (t1i.K1 = 1) AND
(((t2i.K1r = t1a.K1 AND t2i.rowTimestamp > t2a.rowTimestamp ) OR
(t2i.rowTimestamp = t2a.rowTimestamp AND t2i.K2 > t2a.K2))
OR (t2i.K2 IS NULL))
WHERE
t2a.K1r = 1 AND t2i.K2 IS NULL;
K1 Name K2 K1r rowTimestamp Event K2B K1rB rowTimestampB EventB
1 T1Row1 3 1 2015-04-13 10:42:12 T1Row1Event3 NULL NULL NULL NULL
EXPLAIN EXTENDED SELECT t1a.*, t2a.*,
t2i.K2 AS K2B, t2i.K1r AS K1rB,
t2i.rowTimestamp AS rowTimestampB, t2i.Event AS EventB
FROM
t1 t1a JOIN t2 t2a ON t2a.K1r = t1a.K1
LEFT JOIN
( t1 t1i LEFT JOIN t2 t2i ON t2i.K1r = t1i.K1)
ON (t1i.K1 = 1) AND
(((t2i.K1r = t1a.K1 AND t2i.rowTimestamp > t2a.rowTimestamp ) OR
(t2i.rowTimestamp = t2a.rowTimestamp AND t2i.K2 > t2a.K2))
OR (t2i.K2 IS NULL))
WHERE
t2a.K1r = 1 AND t2i.K2 IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1a const PRIMARY PRIMARY 4 const 1 100.00
1 SIMPLE t2a ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1i const PRIMARY PRIMARY 4 const 1 100.00 Using index
1 SIMPLE t2i ALL NULL NULL NULL NULL 3 100.00 Using where; Not exists
Warnings:
Note 1003 select 1 AS `K1`,'T1Row1' AS `Name`,`test`.`t2a`.`K2` AS `K2`,`test`.`t2a`.`K1r` AS `K1r`,`test`.`t2a`.`rowTimestamp` AS `rowTimestamp`,`test`.`t2a`.`Event` AS `Event`,`test`.`t2i`.`K2` AS `K2B`,`test`.`t2i`.`K1r` AS `K1rB`,`test`.`t2i`.`rowTimestamp` AS `rowTimestampB`,`test`.`t2i`.`Event` AS `EventB` from `test`.`t1` `t1a` join `test`.`t2` `t2a` left join (`test`.`t1` `t1i` left join `test`.`t2` `t2i` on((`test`.`t2i`.`K1r` = 1))) on(((`test`.`t1i`.`K1` = 1) and (((`test`.`t2i`.`K1r` = 1) and (`test`.`t2i`.`rowTimestamp` > `test`.`t2a`.`rowTimestamp`)) or ((`test`.`t2i`.`rowTimestamp` = `test`.`t2a`.`rowTimestamp`) and (`test`.`t2i`.`K2` > `test`.`t2a`.`K2`)) or isnull(`test`.`t2i`.`K2`)))) where ((`test`.`t2a`.`K1r` = 1) and isnull(`test`.`t2i`.`K2`))
CREATE VIEW v1 AS
SELECT t2i.*
FROM t1 as t1i LEFT JOIN t2 as t2i ON t2i.K1r = t1i.K1
WHERE t1i.K1 = 1 ;
SELECT
t1a.*, t2a.*, t2b.K2 as K2B, t2b.K1r as K1rB,
t2b.rowTimestamp as rowTimestampB, t2b.Event as EventB
FROM
t1 as t1a JOIN t2 as t2a ON t2a.K1r = t1a.K1
LEFT JOIN
v1 as t2b
ON ((t2b.K1r = t1a.K1 AND t2b.rowTimestamp > t2a.rowTimestamp) OR
(t2b.rowTimestamp = t2a.rowTimestamp AND t2b.K2 > t2a.K2))
OR (t2b.K2 IS NULL)
WHERE
t1a.K1 = 1 AND
t2b.K2 IS NULL;
K1 Name K2 K1r rowTimestamp Event K2B K1rB rowTimestampB EventB
1 T1Row1 3 1 2015-04-13 10:42:12 T1Row1Event3 NULL NULL NULL NULL
EXPLAIN EXTENDED SELECT
t1a.*, t2a.*, t2b.K2 as K2B, t2b.K1r as K1rB,
t2b.rowTimestamp as rowTimestampB, t2b.Event as EventB
FROM
t1 as t1a JOIN t2 as t2a ON t2a.K1r = t1a.K1
LEFT JOIN
v1 as t2b
ON ((t2b.K1r = t1a.K1 AND t2b.rowTimestamp > t2a.rowTimestamp) OR
(t2b.rowTimestamp = t2a.rowTimestamp AND t2b.K2 > t2a.K2))
OR (t2b.K2 IS NULL)
WHERE
t1a.K1 = 1 AND
t2b.K2 IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1a const PRIMARY PRIMARY 4 const 1 100.00
1 SIMPLE t2a ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1i const PRIMARY PRIMARY 4 const 1 100.00 Using index
1 SIMPLE t2i ALL NULL NULL NULL NULL 3 100.00 Using where; Not exists
Warnings:
Note 1003 select 1 AS `K1`,'T1Row1' AS `Name`,`t2a`.`K2` AS `K2`,`t2a`.`K1r` AS `K1r`,`t2a`.`rowTimestamp` AS `rowTimestamp`,`t2a`.`Event` AS `Event`,`test`.`t2i`.`K2` AS `K2B`,`test`.`t2i`.`K1r` AS `K1rB`,`test`.`t2i`.`rowTimestamp` AS `rowTimestampB`,`test`.`t2i`.`Event` AS `EventB` from `test`.`t1` `t1a` join `test`.`t2` `t2a` left join (`test`.`t1` `t1i` left join `test`.`t2` `t2i` on((`test`.`t2i`.`K1r` = 1))) on(((`test`.`t1i`.`K1` = 1) and (((`test`.`t2i`.`K1r` = 1) and (`test`.`t2i`.`rowTimestamp` > `t2a`.`rowTimestamp`)) or ((`test`.`t2i`.`rowTimestamp` = `t2a`.`rowTimestamp`) and (`test`.`t2i`.`K2` > `t2a`.`K2`)) or isnull(`test`.`t2i`.`K2`)))) where ((`t2a`.`K1r` = 1) and isnull(`test`.`t2i`.`K2`))
DROP VIEW v1;
DROP TABLE t1,t2;
set optimizer_search_depth= @tmp_mdev621;
CREATE TABLE t5 (a int, b int, c int, PRIMARY KEY(a), KEY b_i (b));
CREATE TABLE t6 (a int, b int, c int, PRIMARY KEY(a), KEY b_i (b));
@@ -1309,5 +1309,74 @@ LEFT JOIN t4 AS alias5
JOIN t5 ON alias5.f5
ON alias2.f3 ON alias1.f2;
DROP TABLE t1,t2,t3,t4,t5;
set optimizer_search_depth= @tmp_mdev621;

--echo #
--echo # MDEV-7992: Nested left joins + 'not exists' optimization
--echo #

CREATE TABLE t1(
K1 INT PRIMARY KEY,
Name VARCHAR(15)
);

INSERT INTO t1 VALUES
(1,'T1Row1'), (2,'T1Row2');


CREATE TABLE t2(
K2 INT PRIMARY KEY,
K1r INT,
rowTimestamp DATETIME,
Event VARCHAR(15)
);

INSERT INTO t2 VALUES
(1, 1, '2015-04-13 10:42:11' ,'T1Row1Event1'),
(2, 1, '2015-04-13 10:42:12' ,'T1Row1Event2'),
(3, 1, '2015-04-13 10:42:12' ,'T1Row1Event3');

let $q1=
SELECT t1a.*, t2a.*,
t2i.K2 AS K2B, t2i.K1r AS K1rB,
t2i.rowTimestamp AS rowTimestampB, t2i.Event AS EventB
FROM
t1 t1a JOIN t2 t2a ON t2a.K1r = t1a.K1
LEFT JOIN
( t1 t1i LEFT JOIN t2 t2i ON t2i.K1r = t1i.K1)
ON (t1i.K1 = 1) AND
(((t2i.K1r = t1a.K1 AND t2i.rowTimestamp > t2a.rowTimestamp ) OR
(t2i.rowTimestamp = t2a.rowTimestamp AND t2i.K2 > t2a.K2))
OR (t2i.K2 IS NULL))
WHERE
t2a.K1r = 1 AND t2i.K2 IS NULL;

eval $q1;
eval EXPLAIN EXTENDED $q1;

CREATE VIEW v1 AS
SELECT t2i.*
FROM t1 as t1i LEFT JOIN t2 as t2i ON t2i.K1r = t1i.K1
WHERE t1i.K1 = 1 ;

let $q2=
SELECT
t1a.*, t2a.*, t2b.K2 as K2B, t2b.K1r as K1rB,
t2b.rowTimestamp as rowTimestampB, t2b.Event as EventB
FROM
t1 as t1a JOIN t2 as t2a ON t2a.K1r = t1a.K1
LEFT JOIN
v1 as t2b
ON ((t2b.K1r = t1a.K1 AND t2b.rowTimestamp > t2a.rowTimestamp) OR
(t2b.rowTimestamp = t2a.rowTimestamp AND t2b.K2 > t2a.K2))
OR (t2b.K2 IS NULL)
WHERE
t1a.K1 = 1 AND
t2b.K2 IS NULL;

eval $q2;
eval EXPLAIN EXTENDED $q2;

DROP VIEW v1;
DROP TABLE t1,t2;

set optimizer_search_depth= @tmp_mdev621;

0 comments on commit ac78927

Please sign in to comment.
You can’t perform that action at this time.