mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
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.
This commit is contained in:
@ -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;
|
||||
|
@ -7793,8 +7793,6 @@ get_best_combination(JOIN *join)
|
||||
form=join->table[tablenr]=j->table;
|
||||
used_tables|= form->map;
|
||||
form->reginfo.join_tab=j;
|
||||
if (!*j->on_expr_ref)
|
||||
form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
|
||||
DBUG_PRINT("info",("type: %d", j->type));
|
||||
if (j->type == JT_CONST)
|
||||
goto loop_end; // Handled in make_join_stat..
|
||||
@ -8626,6 +8624,9 @@ make_outerjoin_info(JOIN *join)
|
||||
if (embedding && !embedding->is_active_sjm())
|
||||
tab->first_upper= embedding->nested_join->first_nested;
|
||||
}
|
||||
else if (!embedding)
|
||||
tab->table->reginfo.not_exists_optimize= 0;
|
||||
|
||||
for ( ; embedding ; embedding= embedding->embedding)
|
||||
{
|
||||
if (embedding->is_active_sjm())
|
||||
@ -8635,7 +8636,10 @@ make_outerjoin_info(JOIN *join)
|
||||
}
|
||||
/* Ignore sj-nests: */
|
||||
if (!(embedding->on_expr && embedding->outer_join))
|
||||
{
|
||||
tab->table->reginfo.not_exists_optimize= 0;
|
||||
continue;
|
||||
}
|
||||
NESTED_JOIN *nested_join= embedding->nested_join;
|
||||
if (!nested_join->counter)
|
||||
{
|
||||
@ -8651,17 +8655,10 @@ make_outerjoin_info(JOIN *join)
|
||||
}
|
||||
if (!tab->first_inner)
|
||||
tab->first_inner= nested_join->first_nested;
|
||||
if (tab->table->reginfo.not_exists_optimize)
|
||||
tab->first_inner->table->reginfo.not_exists_optimize= 1;
|
||||
if (++nested_join->counter < nested_join->n_tables)
|
||||
break;
|
||||
/* Table tab is the last inner table for nested join. */
|
||||
nested_join->first_nested->last_inner= tab;
|
||||
if (tab->first_inner->table->reginfo.not_exists_optimize)
|
||||
{
|
||||
for (JOIN_TAB *join_tab= tab->first_inner; join_tab <= tab; join_tab++)
|
||||
join_tab->table->reginfo.not_exists_optimize= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
@ -17099,32 +17096,41 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
|
||||
first_unmatched->found= 1;
|
||||
for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
|
||||
{
|
||||
/*
|
||||
Check whether 'not exists' optimization can be used here.
|
||||
If tab->table->reginfo.not_exists_optimize is set to true
|
||||
then WHERE contains a conjunctive predicate IS NULL over
|
||||
a non-nullable field of tab. When activated this predicate
|
||||
will filter out all records with matches for the left part
|
||||
of the outer join whose inner tables start from the
|
||||
first_unmatched table and include table tab. To safely use
|
||||
'not exists' optimization we have to check that the
|
||||
IS NULL predicate is really activated, i.e. all guards
|
||||
that wrap it are in the 'open' state.
|
||||
*/
|
||||
bool not_exists_opt_is_applicable=
|
||||
tab->table->reginfo.not_exists_optimize;
|
||||
for (JOIN_TAB *first_upper= first_unmatched->first_upper;
|
||||
not_exists_opt_is_applicable && first_upper;
|
||||
first_upper= first_upper->first_upper)
|
||||
{
|
||||
if (!first_upper->found)
|
||||
not_exists_opt_is_applicable= false;
|
||||
}
|
||||
/* Check all predicates that has just been activated. */
|
||||
/*
|
||||
Actually all predicates non-guarded by first_unmatched->found
|
||||
will be re-evaluated again. It could be fixed, but, probably,
|
||||
it's not worth doing now.
|
||||
*/
|
||||
/*
|
||||
not_exists_optimize has been created from a
|
||||
select_cond containing 'is_null'. This 'is_null'
|
||||
predicate is still present on any 'tab' with
|
||||
'not_exists_optimize'. Furthermore, the usual rules
|
||||
for condition guards also applies for
|
||||
'not_exists_optimize' -> When 'is_null==false' we
|
||||
know all cond. guards are open and we can apply
|
||||
the 'not_exists_optimize'.
|
||||
*/
|
||||
DBUG_ASSERT(!(tab->table->reginfo.not_exists_optimize &&
|
||||
!tab->select_cond));
|
||||
|
||||
if (tab->select_cond && !tab->select_cond->val_int())
|
||||
{
|
||||
/* The condition attached to table tab is false */
|
||||
|
||||
if (tab == join_tab)
|
||||
{
|
||||
found= 0;
|
||||
if (not_exists_opt_is_applicable)
|
||||
DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -17133,20 +17139,9 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
|
||||
not to the last table of the current nest level.
|
||||
*/
|
||||
join->return_tab= tab;
|
||||
}
|
||||
|
||||
if (tab->table->reginfo.not_exists_optimize)
|
||||
{
|
||||
/*
|
||||
When not_exists_optimize is set: No need to further
|
||||
explore more rows of 'tab' for this partial result.
|
||||
Any found 'tab' matches are known to evaluate to 'false'.
|
||||
Returning .._NO_MORE_ROWS will skip rem. 'tab' rows.
|
||||
*/
|
||||
if (not_exists_opt_is_applicable)
|
||||
DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
|
||||
}
|
||||
else if (tab != join_tab)
|
||||
{
|
||||
else
|
||||
DBUG_RETURN(NESTED_LOOP_OK);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user