polardbxengine/mysql-test/r/derived_correlated.result

3391 lines
143 KiB
Plaintext

set optimizer_trace_max_mem_size=10000000,@@session.optimizer_trace="enabled=on";
# WL#461: allow outer references in derived tables and CTEs
create table t1(a int, b int);
insert into t1 (a) values(1),(2);
create table t2 select * from t1;
analyze table t1,t2;
Table Op Msg_type Msg_text
test.t1 analyze status OK
test.t2 analyze status OK
set optimizer_switch='derived_merge=on';
# Deep nesting: all intermediate subqueries are marked DEPENDENT
explain select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select t1.a) dt1))dt3)dt4);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
5 DEPENDENT SUBQUERY <derived6> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
6 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #6 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (0 <> (/* select#2 */ select count(0) from `test`.`t1` `t2` where true))
select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select t1.a) dt1))dt3)dt4);
a b
1 NULL
2 NULL
# If reference is removed, not DEPENDENT
explain select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select 42) dt1))dt3)dt4);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
5 SUBQUERY <derived6> NULL system NULL NULL NULL NULL 1 100.00 NULL
6 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where true
select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select 42) dt1))dt3)dt4);
a b
1 NULL
2 NULL
# Outer ref is in SELECT list of derived table's definition
explain select
(select dt.a from
(select t1.a as a, t2.a as b from t2) dt where dt.b=t1.a)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 50.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `test`.`t1`.`a` from `test`.`t2` where (`test`.`t2`.`a` = `test`.`t1`.`a`)) AS `subq` from `test`.`t1`
select
(select dt.a from
(select t1.a as a, t2.a as b from t2) dt where dt.b=t1.a)
as subq
from t1;
subq
1
2
# In WHERE
explain select
(select dt.b from
(select t2.a as b from t2 where t1.a=t2.a) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 50.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`)) AS `subq` from `test`.`t1`
select
(select dt.b from
(select t2.a as b from t2 where t1.a=t2.a) dt)
as subq
from t1;
subq
1
2
# In GROUP BY
explain select
(select dt.b from
(select sum(t2.a) as b from t2 group by t1.a) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using temporary
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select sum(`test`.`t2`.`a`) AS `b` from `test`.`t2` group by `test`.`t1`.`a`) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select sum(t2.a) as b from t2 group by t1.a) dt)
as subq
from t1;
subq
3
3
# In HAVING
explain select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-1) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 't1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select sum(`test`.`t2`.`a`) AS `b` from `test`.`t2` having (`test`.`t1`.`a` = (sum(`test`.`t2`.`a`) - 1))) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-1) dt)
as subq
from t1;
subq
NULL
3
explain select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-2) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 't1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select sum(`test`.`t2`.`a`) AS `b` from `test`.`t2` having (`test`.`t1`.`a` = (sum(`test`.`t2`.`a`) - 2))) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-2) dt)
as subq
from t1;
subq
3
NULL
# In ORDER BY
explain select
(select dt.b from
(select t2.a as b from t2 order by if(t1.a=1,t2.a,-t2.a) limit 1) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select `test`.`t2`.`a` AS `b` from `test`.`t2` order by if((`test`.`t1`.`a` = 1),`test`.`t2`.`a`,-(`test`.`t2`.`a`)) limit 1) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select t2.a as b from t2 order by if(t1.a=1,t2.a,-t2.a) limit 1) dt)
as subq
from t1;
subq
1
2
# In window functions
explain select
(select dt.b from
(select t2.a, sum(t1.a*10+t2.a) over (order by if(t1.a=1,t2.a,-t2.a)) as b
from t2) dt where dt.a=1)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 const 1 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using filesort
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 3598 To get information about window functions use EXPLAIN FORMAT=JSON
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select `test`.`t2`.`a` AS `a`,sum(((`test`.`t1`.`a` * 10) + `test`.`t2`.`a`)) OVER (ORDER BY if((`test`.`t1`.`a` = 1),`test`.`t2`.`a`,-(`test`.`t2`.`a`)) ) AS `b` from `test`.`t2`) `dt` where (`dt`.`a` = 1)) AS `subq` from `test`.`t1`
select
(select dt.b from
(select t2.a, sum(t1.a*10+t2.a) over (order by if(t1.a=1,t2.a,-t2.a)) as b
from t2) dt where dt.a=1)
as subq
from t1;
subq
11
43
# CTE referenced twice
explain select
(with dt as (select t1.a as a, t2.a as b from t2)
select dt2.a from dt dt1, dt dt2 where dt1.b=t1.a and dt2.b=dt1.b)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 50.00 Using where
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 50.00 Using where; Using join buffer (Block Nested Loop)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `test`.`t1`.`a` from `test`.`t2` join `test`.`t2` where ((`test`.`t2`.`a` = `test`.`t2`.`a`) and (`test`.`t2`.`a` = `test`.`t1`.`a`))) AS `subq` from `test`.`t1`
select
(with dt as (select t1.a as a, t2.a as b from t2)
select dt2.a from dt dt1, dt dt2 where dt1.b=t1.a and dt2.b=dt1.b)
as subq
from t1;
subq
1
2
Recursive CTE
select
(with recursive dt as
(select t1.a as a union select a+1 from dt where a<10)
select dt1.a from dt dt1 where dt1.a=t1.a
) as subq
from t1;
subq
1
2
select
(with recursive dt as
(select t1.a as a union select a+1 from dt where a<10)
select concat(count(*), ' - ', avg(dt.a)) from dt
) as subq
from t1;
subq
10 - 5.5000
9 - 6.0000
select
(with recursive dt as
(select t1.a as a union all select a+1 from dt where a<10)
select concat(count(*), ' - ', avg(dt.a)) from dt
) as subq
from t1;
subq
10 - 5.5000
9 - 6.0000
select
(with dt as (select t1.a as a, t2.a as b from t2)
select dt2.a from dt dt1, dt dt2 where dt1.b=t1.a and dt2.b=dt1.b)
as subq
from t1;
subq
1
2
# Two references to same CTE at different levels of nesting.
explain select (with dt as (select t1.a as a from t2 limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 func 2 100.00 Using where; Using index
4 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select (with `dt` as (/* select#3 */ select `test`.`t1`.`a` AS `a` from `test`.`t2` limit 1) /* select#2 */ select `dt1`.`a` from `dt` `dt1` where (`dt1`.`a` = (/* select#4 */ select `dt2`.`a` from `dt` `dt2`))) AS `subq` from `test`.`t1`
explain format=tree select (with dt as (select t1.a as a from t2 limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
EXPLAIN
-> Table scan on t1 (cost=0.45 rows=2)
-> Select #2 (subquery in projection; dependent)
-> Filter: (dt1.a = (select #4))
-> Index lookup on dt1 using <auto_key0> (a=(select #4))
-> Materialize CTE dt if needed
-> Limit: 1 row(s)
-> Table scan on t2 (cost=0.45 rows=2)
-> Select #4 (subquery in condition; dependent)
-> Table scan on dt2
-> Materialize CTE dt if needed (query plan printed elsewhere)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #5 was resolved in SELECT #1
select (with dt as (select t1.a as a from t2 limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
subq
1
2
explain select (with dt as (select t2.a as a from t2 having t1.a=t2.a limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 func 2 100.00 Using where; Using index
4 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 't1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 't1.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select (with `dt` as (/* select#3 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` having (`test`.`t1`.`a` = `test`.`t2`.`a`) limit 1) /* select#2 */ select `dt1`.`a` from `dt` `dt1` where (`dt1`.`a` = (/* select#4 */ select `dt2`.`a` from `dt` `dt2`))) AS `subq` from `test`.`t1`
select (with dt as (select t2.a as a from t2 having t1.a=t2.a limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
subq
1
2
# Scope of outer ref in CTE
select (select * from (select t1.a) cte) from t1;
(select * from (select t1.a) cte)
1
2
select (with cte as (select t1.a) select * from cte) from t1;
(with cte as (select t1.a) select * from cte)
1
2
with cte as (select t1.a) select (select * from cte) from t1;
ERROR 42S02: Unknown table 't1' in field list
# NOT IN(subquery using derived), handled with subquery materialization
explain select * from t1
where a not in (select dt.f+1 from (select t2.a as f from t2) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` where <if>(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = (`test`.`t2`.`a` + 1)) or ((`test`.`t2`.`a` + 1) is null)), true) having <if>(outer_field_is_not_null, <is_not_null_test>((`test`.`t2`.`a` + 1)), true)) is false)
select * from t1
where a not in (select dt.f+1 from (select t2.a as f from t2) dt);
a b
1 NULL
# Now put an outer reference inside derived table:
# subquery is properly seen as correlated and subquery
# materialization is thus not used.
explain select * from t1
where a not in (select dt.f+1 from (select 0*t1.a+t2.a as f from t2) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` where <if>(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = (((0 * `test`.`t1`.`a`) + `test`.`t2`.`a`) + 1)) or ((((0 * `test`.`t1`.`a`) + `test`.`t2`.`a`) + 1) is null)), true) having <if>(outer_field_is_not_null, <is_not_null_test>((((0 * `test`.`t1`.`a`) + `test`.`t2`.`a`) + 1)), true)) is false)
select * from t1
where a not in (select dt.f+1 from (select 0*t1.a+t2.a as f from t2) dt);
a b
1 NULL
# Verify that a non-lateral derived table with an outer
# reference makes the semijoin be correlated and thus blocks
# semijoin-materialization-scan.
create table t11 (a int);
insert into t11
with recursive cte as (select 1 as a union all select a+1 from cte where a<124)
select * from cte;
alter table t11 add index(a);
create table t12 like t11;
analyze table t11,t12;
Table Op Msg_type Msg_text
test.t11 analyze status OK
test.t12 analyze status OK
# No outer ref: mat-scan chosen
explain select
/*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */
* from t11 where a in (select /*+ QB_NAME(subq1) NO_MERGE(dt) */ *
from (select t12.a from t12) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 Using where
1 PRIMARY t11 NULL ref a a 5 <subquery2>.a 1 100.00 Using index
2 MATERIALIZED <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DERIVED t12 NULL index NULL a 5 NULL 1 100.00 Using index
Warnings:
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) NO_MERGE(`dt`@`subq1`) */ `test`.`t11`.`a` AS `a` from `test`.`t11` semi join ((/* select#3 */ select `test`.`t12`.`a` AS `a` from `test`.`t12`) `dt`) where (`test`.`t11`.`a` = `<subquery2>`.`a`)
# outer ref: mat-scan not chosen
explain select
/*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */
* from t11 where a in (select /*+ QB_NAME(subq1) NO_MERGE(dt) */ *
from (select t12.a+0*t11.a from t12) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 NULL index a a 5 NULL 124 100.00 Using where; Using index; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 9 test.t11.a 2 100.00 Using where; Using index; Start temporary; End temporary
3 DEPENDENT DERIVED t12 NULL index NULL a 5 NULL 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.t11.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) NO_MERGE(`dt`@`subq1`) */ `test`.`t11`.`a` AS `a` from `test`.`t11` semi join (lateral (/* select#3 */ select (`test`.`t12`.`a` + (0 * `test`.`t11`.`a`)) AS `t12.a+0*t11.a` from `test`.`t12`) `dt`) where (`test`.`t11`.`a` = `dt`.`t12.a+0*t11.a`)
DROP TABLE t11,t12;
LATERAL
# prevents join buffer if materialized (but not if merged)
explain select dt.a from t1, lateral (select t1.a from t2) dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 SIMPLE t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2`
# no right join
explain select dt.a from t1 right join lateral (select t1.a from t2) dt on 1;
ERROR HY000: INNER or LEFT JOIN must be used for LATERAL references made by 'dt'
# no bad left join either
explain select dt.a from lateral (select t1.a from t2) dt left join t1 on 1;
ERROR 42S22: Unknown column 't1.a' in 'field list'
# more complex case
explain SELECT * FROM t1
LEFT JOIN
lateral (select t1.a) as dt ON t1.a=dt.a
RIGHT JOIN
lateral (select dt.a) as dt1 ON dt.a=dt1.a;
ERROR HY000: INNER or LEFT JOIN must be used for LATERAL references made by 'dt1'
# LATERAL DT depending on LATERAL DT
explain SELECT * FROM t1
JOIN
lateral (select t1.a) as dt ON t1.a=dt.a
JOIN
lateral (select dt.a) as dt1 ON dt.a=dt1.a;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where; Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using index; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using index
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'dt.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt1`.`a` AS `a` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select `dt`.`a` AS `a`) `dt1` where ((`dt`.`a` = `test`.`t1`.`a`) and (`dt1`.`a` = `test`.`t1`.`a`))
# Placing lateral outer ref in SELECT list then HAVING
select t1.a, dt.a from t1, lateral (select t1.a+t2.a as a from t2) dt;
a a
1 2
1 3
2 3
2 4
select t1.a, dt.a from t1, lateral (select t2.a as a from t2 having t1.a) dt;
a a
1 1
1 2
2 1
2 2
# Inside view
create view v1 as
select t1.a as f1, dt.a as f2
from t1, lateral (select t1.a+t2.a as a from t2) dt;
show create view v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `f1`,`dt`.`a` AS `f2` from (`t1` join lateral (select (`t1`.`a` + `t2`.`a`) AS `a` from `t2`) `dt`) utf8mb4 utf8mb4_0900_ai_ci
select * from v1;
f1 f2
1 2
1 3
2 3
2 4
drop view v1;
# Coverage for various branches in Item_ref::fix_fields
SELECT COUNT(*) FROM t1 GROUP BY t1.a HAVING t1.a IN (SELECT t3.a
FROM t1 AS t3 WHERE t3.b IN (SELECT b FROM t2, lateral (select t1.a) dt));
COUNT(*)
create view v1 as select a, b from t1;
select vq1.b,dt.b from v1 vq1, lateral (select vq1.b) dt;
b b
NULL NULL
NULL NULL
select b from v1 vq1, lateral (select count(*) from v1 vq2 having vq1.b = 3) dt;
b
drop view v1;
SELECT
/*+ SET_VAR(optimizer_switch = 'materialization=off,semijoin=off') */
* FROM t1 AS ta, lateral (select 1 WHERE ta.a IN (SELECT b FROM t2 AS tb WHERE tb.b >= SOME(SELECT SUM(tc.a) as sg FROM t1 as tc GROUP BY tc.b HAVING ta.a=tc.b))) dt;
a b 1
select (select dt.a from (select 1 as a, t2.a as b from t2 having
t1.a) dt where dt.b=t1.a) as subq from t1;
subq
1
1
select (select dt.a from (select 1 as a, 3 as b from t2 having t1.a)
dt where dt.b=t1.a) as subq from t1;
subq
NULL
NULL
# Aggregation in outer context
select (select f from (select max(t1.a) as f) as dt) as g from t1;
g
2
select (select f from lateral (select max(t1.a) as f) as dt) as g from t1;
g
2
# LATERAL doesn't allow an aggregate to resolve to the
# immediate parent (because reading of FROM tables happens
# before aggregation). So it resolves in the derived table, so
# the outer query doesn't produce a single-row result.
select t1.a, f from t1, lateral (select max(t1.a) as f) as dt;
a f
1 1
2 2
# We support CTE inside derived table
select * from t1,
lateral (with qn as (select t1.a) select (select max(a) from qn)) as dt;
a b (select max(a) from qn)
1 NULL 1
2 NULL 2
# Coverage for crash in Item_ident::fix_after_pullout:
# when we merge a derived table contained in a derived table,
# and the merged one contains an outer ref to the top query.
select (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) from t1;
(select * from (select * from (select t1.a from t2) as dt limit 1) dt2)
1
2
# Semijoin containing a correlated derived table, DT must
# become LATERAL
explain select a from t1 where a in (select a from (select t1.a) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using index; FirstMatch(t1)
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (lateral (/* select#3 */ select `test`.`t1`.`a` AS `a`) `dt`) where (`dt`.`a` = `test`.`t1`.`a`)
select a from t1 where a in (select a from (select t1.a) dt);
a
1
2
create table t3 as with recursive cte as (select 1 as a union select a+1 from cte where a<20) select * from cte;
analyze table t3;
Table Op Msg_type Msg_text
test.t3 analyze status OK
explain select min(a),max(a) from t3 where a in (select /*+ no_merge() */ a from (select t3.a from t1) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 20 100.00 Using where; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 9 test.t3.a 2 100.00 Using index; FirstMatch(t3)
3 DEPENDENT DERIVED t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t3.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_MERGE(@`select#2`) */ min(`test`.`t3`.`a`) AS `min(a)`,max(`test`.`t3`.`a`) AS `max(a)` from `test`.`t3` semi join (lateral (/* select#3 */ select `test`.`t3`.`a` AS `a` from `test`.`t1`) `dt`) where (`dt`.`a` = `test`.`t3`.`a`)
select min(a),max(a) from t3 where a in (select /*+ no_merge() */ a from (select t3.a from t1) dt);
min(a) max(a)
1 20
drop table t3;
# DT containing a correlated DT which must become LATERAL
explain format=tree select * from t1, lateral (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) dt3;
EXPLAIN
-> Nested loop inner join
-> Invalidate materialized tables (row from t1) (cost=0.45 rows=2)
-> Table scan on t1 (cost=0.45 rows=2)
-> Table scan on dt2
-> Materialize (invalidate on row from t1)
-> Limit: 1 row(s)
-> Table scan on t2 (cost=0.45 rows=2)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
explain select * from t1, lateral (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) dt3;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt2`.`a` AS `a` from `test`.`t1` join lateral (/* select#3 */ select `test`.`t1`.`a` AS `a` from `test`.`t2` limit 1) `dt2`
select * from t1, lateral (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) dt3;
a b a
1 NULL 1
2 NULL 2
explain select * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived4>)
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`dt2`.`a` AS `a` from `test`.`t1` `t0` join `test`.`t1` join lateral (/* select#4 */ select `test`.`t0`.`a` AS `a` from `test`.`t2` limit 1) `dt2`
select * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
a b a
1 NULL 1
1 NULL 1
2 NULL 2
2 NULL 2
explain select /*+ no_merge() */ * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 4 100.00 NULL
2 DEPENDENT DERIVED t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
4 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_MERGE(@`select#1`) */ `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`dt4`.`a` AS `a` from `test`.`t1` `t0` join lateral (/* select#2 */ select `dt2`.`a` AS `a` from `test`.`t1` join (/* select#4 */ select `test`.`t0`.`a` AS `a` from `test`.`t2` limit 1) `dt2`) `dt4`
select /*+ no_merge() */ * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
a b a
1 NULL 1
1 NULL 1
2 NULL 2
2 NULL 2
explain select * from t1, lateral (select * from (select 42) t1, (select t1.a) dt2) dt3;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <derived3> NULL system NULL NULL NULL NULL 1 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived4>)
1 PRIMARY <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,'42' AS `42`,`dt2`.`a` AS `a` from `test`.`t1` join lateral (/* select#4 */ select `test`.`t1`.`a` AS `a`) `dt2`
select * from t1, lateral (select * from (select 42) t1, (select t1.a) dt2) dt3;
a b 42 a
1 NULL 42 1
2 NULL 42 2
without semijoin: index_subquery needs to re-materialize
explain select a from t1 where a in (select /*+ no_semijoin() */ a from (select t1.a) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY <derived3> NULL index_subquery <auto_key0> <auto_key0> 5 func 2 100.00 Using index
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in dt on <auto_key0>)))
select a from t1 where a in (select /*+ no_semijoin() */ a from (select t1.a) dt);
a
1
2
select a from t1 where a in (with cte as (select t1.a)
select /*+ no_semijoin() */ a from cte);
a
1
2
# Count rematerializations
# In all three plans, handler_write is 2, showing that we
# rematerialize only when necessary (when row of t1 changes)
explain select straight_join * from t1, t2, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select straight_join `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t1` join `test`.`t2` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select straight_join * from t1, t2, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 1
2 NULL 1 NULL 2
2 NULL 2 NULL 2
# when a row of t1 produces two rows of t2 passed to "dt",
# it still makes one materialization.
show status like "handler_write";
Variable_name Value
Handler_write 2
explain select straight_join * from t1, lateral (select t1.a) as dt, t2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select straight_join `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join `test`.`t2`
flush status;
select straight_join * from t1, lateral (select t1.a) as dt, t2;
a b a a b
1 NULL 1 1 NULL
1 NULL 1 2 NULL
2 NULL 2 1 NULL
2 NULL 2 2 NULL
show status like "handler_write";
Variable_name Value
Handler_write 2
explain select straight_join * from t2, t1, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>); Using join buffer (Block Nested Loop)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select straight_join `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select straight_join * from t2, t1, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 2
2 NULL 1 NULL 1
2 NULL 2 NULL 2
# Due to join buffer, order t2-t1 produces rows as a
# non-buffered t1-t2 plan: t1 buffers all rows of t2, then for
# each row of t1 it's joined to all rows of t2 and passed to t2;
# when a row of t1 produces two rows of t2 passed to "dt",
# it still makes one materialization.
show status like "handler_write";
Variable_name Value
Handler_write 2
# Let the planner find the best plan.
# It doesn't work so well, because of
# optimizer_prune_level=1 (see bug#28629788): order specified by
# the user is sorted by number of rows, which leaves it
# unchanged (Card(t1)=Card(t2)=Card(dt)); then it is the first
# explored plan so it's explored in full, and later t1-dt is rejected as
# more expensive than t1-t2. Whereas if t1-dt had been explored
# deeper, we'd see t1-dt-t2 is actually the cheapest, because
# it reads dt the least number of times (and dt has a high read
# cost because Temptable::scan_time() is incredibly high but
# that's another issue; see bug#28631100).
# t2 cannot use join buffering as between "dt" and its
# dependency t1: join buffering would interlace rows of t1
# thus cause more rematerializations.
explain select * from t1, t2, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t1` join `test`.`t2` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select * from t1, t2, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 1
2 NULL 1 NULL 2
2 NULL 2 NULL 2
show status like "handler_write";
Variable_name Value
Handler_write 2
# This one finds the best plan. Yes we simply swapped tables in the query,
# and it yields a different plan. This is because the order specified by
# the user is sorted by number of rows, which leaves it
# unchanged (Card(t1)=Card(t2)=Card(dt), then it is the first
# explored plan so it's explored in full and so is never pruned by
# prune_level=1, and it is the best plan. Best as: it reads
# "dt" less, and t2 uses join buffering (which is ok as it's
# after "dt").
# If prune_level=0, all 3 variants here produce this plan.
explain select * from t1, lateral (select t1.a) as dt, t2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join `test`.`t2`
flush status;
select * from t1, lateral (select t1.a) as dt, t2;
a b a a b
1 NULL 1 1 NULL
1 NULL 1 2 NULL
2 NULL 2 1 NULL
2 NULL 2 2 NULL
show status like "handler_write";
Variable_name Value
Handler_write 2
# This one is intermediate: t1 uses join buffer (good), but
# "dt" is last (bad, as it has high scan cost).
explain select * from t2, t1, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>); Using join buffer (Block Nested Loop)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select * from t2, t1, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 2
2 NULL 1 NULL 1
2 NULL 2 NULL 2
show status like "handler_write";
Variable_name Value
Handler_write 2
# Show the trace of planning of lateral derived tables
explain select * from t1, lateral (select t1.a from t2 as t3, t2 as t4) as dt, t2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 SIMPLE t3 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
1 SIMPLE t4 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
1 SIMPLE t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` `t3` join `test`.`t2` `t4` join `test`.`t2`
select trace from information_schema.optimizer_trace;
trace
{
"steps": [
{
"join_preparation": {
"select#": 1,
"steps": [
{
"join_preparation": {
"select#": 2,
"steps": [
{
"expanded_query": "/* select#2 */ select `t1`.`a` AS `a` from `t2` `t3` join `t2` `t4`"
}
]
}
},
{
"derived": {
"table": "``.`` `dt`",
"select#": 2,
"merged": true
}
},
{
"expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`a` AS `a`,`t2`.`b` AS `b` from `t1` join (`t2` `t3` join `t2` `t4`) join `t2`"
},
{
"transformations_to_nested_joins": {
"transformations": [
"parenthesis_removal"
],
"expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`a` AS `a`,`t2`.`b` AS `b` from `t1` join `t2` `t3` join `t2` `t4` join `t2`"
}
}
]
}
},
{
"join_optimization": {
"select#": 1,
"steps": [
{
"table_dependencies": [
{
"table": "`t1`",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": [
]
},
{
"table": "`t2` `t3`",
"row_may_be_null": false,
"map_bit": 1,
"depends_on_map_bits": [
]
},
{
"table": "`t2` `t4`",
"row_may_be_null": false,
"map_bit": 2,
"depends_on_map_bits": [
]
},
{
"table": "`t2`",
"row_may_be_null": false,
"map_bit": 3,
"depends_on_map_bits": [
]
}
]
},
{
"rows_estimation": [
{
"table": "`t1`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
},
{
"table": "`t2` `t3`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
},
{
"table": "`t2` `t4`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
},
{
"table": "`t2`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`t1`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"rest_of_plan": [
{
"plan_prefix": [
"`t1`"
],
"table": "`t2` `t3`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 0.65,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 4,
"cost_for_plan": 1.1,
"rest_of_plan": [
{
"plan_prefix": [
"`t1`",
"`t2` `t3`"
],
"table": "`t2` `t4`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 1.05,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 8,
"cost_for_plan": 2.1501,
"rest_of_plan": [
{
"plan_prefix": [
"`t1`",
"`t2` `t3`",
"`t2` `t4`"
],
"table": "`t2`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 1.8501,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 16,
"cost_for_plan": 4.0001,
"chosen": true
}
]
},
{
"plan_prefix": [
"`t1`",
"`t2` `t3`"
],
"table": "`t2`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 1.05,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 8,
"cost_for_plan": 2.1501,
"pruned_by_heuristic": true
}
]
},
{
"plan_prefix": [
"`t1`"
],
"table": "`t2` `t4`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 0.65,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 4,
"cost_for_plan": 1.1,
"pruned_by_heuristic": true
},
{
"plan_prefix": [
"`t1`"
],
"table": "`t2`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 0.65,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 4,
"cost_for_plan": 1.1,
"pruned_by_heuristic": true
}
]
},
{
"plan_prefix": [
],
"table": "`t2` `t3`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"pruned_by_heuristic": true
},
{
"plan_prefix": [
],
"table": "`t2` `t4`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"pruned_by_heuristic": true
},
{
"plan_prefix": [
],
"table": "`t2`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"pruned_by_heuristic": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": null,
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`t1`",
"attached": null
},
{
"table": "`t2` `t3`",
"attached": null
},
{
"table": "`t2` `t4`",
"attached": null
},
{
"table": "`t2`",
"attached": null
}
]
}
},
{
"finalizing_table_conditions": [
]
},
{
"refine_plan": [
{
"table": "`t1`"
},
{
"table": "`t2` `t3`"
},
{
"table": "`t2` `t4`"
},
{
"table": "`t2`"
}
]
}
]
}
},
{
"join_explain": {
"select#": 1,
"steps": [
]
}
}
]
}
# LDT depending on const table only
create table t3(a int) engine=innodb;
insert into t3 values(3);
analyze table t3;
Table Op Msg_type Msg_text
test.t3 analyze status OK
explain select * from t3, lateral (select t3.a+1) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 1 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t3.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`dt`.`t3.a+1` AS `t3.a+1` from `test`.`t3` join lateral (/* select#2 */ select (`test`.`t3`.`a` + 1) AS `t3.a+1`) `dt`
select * from t3, lateral (select t3.a+1) as dt;
a t3.a+1
3 4
drop table t3;
# Two LDTs depending on different tables
explain select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t2.a) as dt2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived3>)
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t2.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt2`.`a` AS `a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select `test`.`t2`.`a` AS `a`) `dt2`
select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t2.a) as dt2;
a b a b a a
1 NULL 1 NULL 1 1
1 NULL 2 NULL 2 1
2 NULL 1 NULL 1 2
2 NULL 2 NULL 2 2
# Two LDTs depending on one same table
explain select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t1.a+1) as dt2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>,<derived3>); Using join buffer (Block Nested Loop)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt2`.`t1.a+1` AS `t1.a+1` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select (`test`.`t1`.`a` + 1) AS `t1.a+1`) `dt2`
explain format=json select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t1.a+1) as dt2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "34.10"
},
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 2,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.20",
"prefix_cost": "0.45",
"data_read_per_join": "32"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 4,
"filtered": "100.00",
"rematerialize": "dt,dt2",
"using_join_buffer": "Block Nested Loop",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.40",
"prefix_cost": "1.10",
"data_read_per_join": "64"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "dt",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 8,
"filtered": "100.00",
"cost_info": {
"read_cost": "10.30",
"eval_cost": "0.80",
"prefix_cost": "12.20",
"data_read_per_join": "128"
},
"used_columns": [
"a"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": true,
"cacheable": true,
"query_block": {
"select_id": 2,
"message": "No tables used"
}
}
}
},
{
"table": {
"table_name": "dt2",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 16,
"filtered": "100.00",
"cost_info": {
"read_cost": "20.30",
"eval_cost": "1.60",
"prefix_cost": "34.10",
"data_read_per_join": "256"
},
"used_columns": [
"t1.a+1"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": true,
"cacheable": true,
"query_block": {
"select_id": 3,
"message": "No tables used"
}
}
}
}
]
}
}
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt2`.`t1.a+1` AS `t1.a+1` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select (`test`.`t1`.`a` + 1) AS `t1.a+1`) `dt2`
select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t1.a+1) as dt2;
a b a b a t1.a+1
1 NULL 1 NULL 1 2
1 NULL 2 NULL 2 3
2 NULL 1 NULL 1 2
2 NULL 2 NULL 2 3
# One LDT depending on two tables. The "rematerialize" tag is
# properly added to the 2nd dependency only.
explain select * from t2, t1, lateral (select t1.a+t2.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t2.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`t1.a+t2.a` AS `t1.a+t2.a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select (`test`.`t1`.`a` + `test`.`t2`.`a`) AS `t1.a+t2.a`) `dt`
explain format=json select * from t2, t1, lateral (select t1.a+t2.a) as dt;
EXPLAIN
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "12.45"
},
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 2,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.20",
"prefix_cost": "0.45",
"data_read_per_join": "32"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 4,
"filtered": "100.00",
"rematerialize": "dt",
"cost_info": {
"read_cost": "0.50",
"eval_cost": "0.40",
"prefix_cost": "1.35",
"data_read_per_join": "64"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "dt",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 8,
"filtered": "100.00",
"cost_info": {
"read_cost": "10.30",
"eval_cost": "0.80",
"prefix_cost": "12.45",
"data_read_per_join": "128"
},
"used_columns": [
"t1.a+t2.a"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": true,
"cacheable": true,
"query_block": {
"select_id": 2,
"message": "No tables used"
}
}
}
}
]
}
}
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t2.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`t1.a+t2.a` AS `t1.a+t2.a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select (`test`.`t1`.`a` + `test`.`t2`.`a`) AS `t1.a+t2.a`) `dt`
select * from t2, t1, lateral (select t1.a+t2.a) as dt;
a b a b t1.a+t2.a
1 NULL 1 NULL 2
1 NULL 2 NULL 3
2 NULL 1 NULL 3
2 NULL 2 NULL 4
select json_extract(trace,"$.steps[*].join_optimization.steps[*].refine_plan") from information_schema.optimizer_trace;
json_extract(trace,"$.steps[*].join_optimization.steps[*].refine_plan")
[[{"table": "`t2`"}, {"table": "`t1`"}, {"table": " `dt`", "rematerialized_for_each_row_of": "t1"}]]
# Test when a dependency of LDT uses BKA: BKA code must
# refresh LDT's content when it provides a row.
set @old_opt_switch=@@optimizer_switch;
set @@optimizer_switch="batched_key_access=on,mrr_cost_based=off";
CREATE TABLE t11 (t11a int, t11b int);
INSERT INTO t11 VALUES (99, NULL),(99, 3),(99,0);
CREATE TABLE t12 (t12a int, t12b int, KEY idx (t12b));
INSERT INTO t12 VALUES (100,0),(150,200),(999, 0),(999, NULL);
ANALYZE TABLE t11,t12;
Table Op Msg_type Msg_text
test.t11 analyze status OK
test.t12 analyze status OK
explain SELECT * FROM t11 LEFT JOIN t12 force index (idx) ON t12.t12b = t11.t11b
JOIN LATERAL (SELECT t12a) dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 NULL ALL NULL NULL NULL NULL 3 100.00 NULL
1 PRIMARY t12 NULL ref idx idx 5 test.t11.t11b 1 100.00 Rematerialize (<derived2>); Using join buffer (Batched Key Access)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t12.t12a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t11`.`t11a` AS `t11a`,`test`.`t11`.`t11b` AS `t11b`,`test`.`t12`.`t12a` AS `t12a`,`test`.`t12`.`t12b` AS `t12b`,`dt`.`t12a` AS `t12a` from `test`.`t11` left join `test`.`t12` FORCE INDEX (`idx`) on((`test`.`t12`.`t12b` = `test`.`t11`.`t11b`)) join lateral (/* select#2 */ select `test`.`t12`.`t12a` AS `t12a`) `dt` where true
flush status;
SELECT * FROM t11 LEFT JOIN t12 force index (idx) ON t12.t12b = t11.t11b
JOIN LATERAL (SELECT t12a) dt;
t11a t11b t12a t12b t12a
99 0 100 0 100
99 0 999 0 999
99 NULL NULL NULL NULL
99 3 NULL NULL NULL
show status like "handler_write";
Variable_name Value
Handler_write 3
DROP TABLE t11,t12;
set @@optimizer_switch=@old_opt_switch;
# Test that with an auto_key on the lateral DT, the index is
# properly emptied and re-filled when re-materializing.
# If index weren't emptied, we'd see too many "11" matches for 2nd
# row of t1; and if not re-filled, we'd see no matches for that.
create table t3 (a int, b int);
insert into t3 values(1, 10), (1, 11), (2, 10), (2, 11);
analyze table t3;
Table Op Msg_type Msg_text
test.t3 analyze status OK
# Note the auto_key with "Using index", to test the index as
# much as possible.
explain select * from t1, lateral (select t3.b from t3 where t3.a=t1.a) dt
where dt.b=t1.a+9;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 SIMPLE t3 NULL ALL NULL NULL NULL NULL 4 25.00 Using where; Using join buffer (Block Nested Loop)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`b` AS `b` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`a`) and (`test`.`t3`.`b` = (`test`.`t1`.`a` + 9)))
select * from t1, lateral (select t3.b from t3 where t3.a=t1.a) dt
where dt.b=t1.a+9;
a b b
1 NULL 10
2 NULL 11
drop table t3;
set optimizer_switch='derived_merge=off';
# Deep nesting: all intermediate subqueries are marked DEPENDENT
explain select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select t1.a) dt1))dt3)dt4);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
5 DEPENDENT SUBQUERY <derived6> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
6 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #6 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (0 <> (/* select#2 */ select count(0) from (/* select#3 */ select `dt3`.`a` AS `a`,`dt3`.`b` AS `b` from (/* select#4 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` `t2` where (2 = (/* select#5 */ select 2 from (/* select#6 */ select `test`.`t1`.`a` AS `a`) `dt1`))) `dt3`) `dt4`))
select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select t1.a) dt1))dt3)dt4);
a b
1 NULL
2 NULL
# If reference is removed, not DEPENDENT
explain select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select 42) dt1))dt3)dt4);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
5 SUBQUERY <derived6> NULL system NULL NULL NULL NULL 1 100.00 NULL
6 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where true
select * from t1 where
(select count(*) from (select * from (select * from t1 t2
where 2=(select 2 from (select 42) dt1))dt3)dt4);
a b
1 NULL
2 NULL
# Outer ref is in SELECT list of derived table's definition
explain select
(select dt.a from
(select t1.a as a, t2.a as b from t2) dt where dt.b=t1.a)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`a` from (/* select#3 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t2`) `dt` where (`dt`.`b` = `test`.`t1`.`a`)) AS `subq` from `test`.`t1`
select
(select dt.a from
(select t1.a as a, t2.a as b from t2) dt where dt.b=t1.a)
as subq
from t1;
subq
1
2
# In WHERE
explain select
(select dt.b from
(select t2.a as b from t2 where t1.a=t2.a) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 50.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select `test`.`t2`.`a` AS `b` from `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`)) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select t2.a as b from t2 where t1.a=t2.a) dt)
as subq
from t1;
subq
1
2
# In GROUP BY
explain select
(select dt.b from
(select sum(t2.a) as b from t2 group by t1.a) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using temporary
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select sum(`test`.`t2`.`a`) AS `b` from `test`.`t2` group by `test`.`t1`.`a`) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select sum(t2.a) as b from t2 group by t1.a) dt)
as subq
from t1;
subq
3
3
# In HAVING
explain select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-1) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 't1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select sum(`test`.`t2`.`a`) AS `b` from `test`.`t2` having (`test`.`t1`.`a` = (sum(`test`.`t2`.`a`) - 1))) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-1) dt)
as subq
from t1;
subq
NULL
3
explain select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-2) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 't1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select sum(`test`.`t2`.`a`) AS `b` from `test`.`t2` having (`test`.`t1`.`a` = (sum(`test`.`t2`.`a`) - 2))) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select sum(t2.a) as b from t2 having t1.a=sum(t2.a)-2) dt)
as subq
from t1;
subq
3
NULL
# In ORDER BY
explain select
(select dt.b from
(select t2.a as b from t2 order by if(t1.a=1,t2.a,-t2.a) limit 1) dt)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select `test`.`t2`.`a` AS `b` from `test`.`t2` order by if((`test`.`t1`.`a` = 1),`test`.`t2`.`a`,-(`test`.`t2`.`a`)) limit 1) `dt`) AS `subq` from `test`.`t1`
select
(select dt.b from
(select t2.a as b from t2 order by if(t1.a=1,t2.a,-t2.a) limit 1) dt)
as subq
from t1;
subq
1
2
# In window functions
explain select
(select dt.b from
(select t2.a, sum(t1.a*10+t2.a) over (order by if(t1.a=1,t2.a,-t2.a)) as b
from t2) dt where dt.a=1)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 const 1 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using filesort
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 3598 To get information about window functions use EXPLAIN FORMAT=JSON
Note 1003 /* select#1 */ select (/* select#2 */ select `dt`.`b` from (/* select#3 */ select `test`.`t2`.`a` AS `a`,sum(((`test`.`t1`.`a` * 10) + `test`.`t2`.`a`)) OVER (ORDER BY if((`test`.`t1`.`a` = 1),`test`.`t2`.`a`,-(`test`.`t2`.`a`)) ) AS `b` from `test`.`t2`) `dt` where (`dt`.`a` = 1)) AS `subq` from `test`.`t1`
select
(select dt.b from
(select t2.a, sum(t1.a*10+t2.a) over (order by if(t1.a=1,t2.a,-t2.a)) as b
from t2) dt where dt.a=1)
as subq
from t1;
subq
11
43
# CTE referenced twice
explain select
(with dt as (select t1.a as a, t2.a as b from t2)
select dt2.a from dt dt1, dt dt2 where dt1.b=t1.a and dt2.b=dt1.b)
as subq
from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using where
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select (with `dt` as (/* select#3 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t2`) /* select#2 */ select `dt2`.`a` from `dt` `dt1` join `dt` `dt2` where ((`dt2`.`b` = `dt1`.`b`) and (`dt1`.`b` = `test`.`t1`.`a`))) AS `subq` from `test`.`t1`
select
(with dt as (select t1.a as a, t2.a as b from t2)
select dt2.a from dt dt1, dt dt2 where dt1.b=t1.a and dt2.b=dt1.b)
as subq
from t1;
subq
1
2
Recursive CTE
select
(with recursive dt as
(select t1.a as a union select a+1 from dt where a<10)
select dt1.a from dt dt1 where dt1.a=t1.a
) as subq
from t1;
subq
1
2
select
(with recursive dt as
(select t1.a as a union select a+1 from dt where a<10)
select concat(count(*), ' - ', avg(dt.a)) from dt
) as subq
from t1;
subq
10 - 5.5000
9 - 6.0000
select
(with recursive dt as
(select t1.a as a union all select a+1 from dt where a<10)
select concat(count(*), ' - ', avg(dt.a)) from dt
) as subq
from t1;
subq
10 - 5.5000
9 - 6.0000
select
(with dt as (select t1.a as a, t2.a as b from t2)
select dt2.a from dt dt1, dt dt2 where dt1.b=t1.a and dt2.b=dt1.b)
as subq
from t1;
subq
1
2
# Two references to same CTE at different levels of nesting.
explain select (with dt as (select t1.a as a from t2 limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 func 2 100.00 Using where; Using index
4 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select (with `dt` as (/* select#3 */ select `test`.`t1`.`a` AS `a` from `test`.`t2` limit 1) /* select#2 */ select `dt1`.`a` from `dt` `dt1` where (`dt1`.`a` = (/* select#4 */ select `dt2`.`a` from `dt` `dt2`))) AS `subq` from `test`.`t1`
explain format=tree select (with dt as (select t1.a as a from t2 limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
EXPLAIN
-> Table scan on t1 (cost=0.45 rows=2)
-> Select #2 (subquery in projection; dependent)
-> Filter: (dt1.a = (select #4))
-> Index lookup on dt1 using <auto_key0> (a=(select #4))
-> Materialize CTE dt if needed
-> Limit: 1 row(s)
-> Table scan on t2 (cost=0.45 rows=2)
-> Select #4 (subquery in condition; dependent)
-> Table scan on dt2
-> Materialize CTE dt if needed (query plan printed elsewhere)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #5 was resolved in SELECT #1
select (with dt as (select t1.a as a from t2 limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
subq
1
2
explain select (with dt as (select t2.a as a from t2 having t1.a=t2.a limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT SUBQUERY <derived3> NULL ref <auto_key0> <auto_key0> 5 func 2 100.00 Using where; Using index
4 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 't1.a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 't1.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select (with `dt` as (/* select#3 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` having (`test`.`t1`.`a` = `test`.`t2`.`a`) limit 1) /* select#2 */ select `dt1`.`a` from `dt` `dt1` where (`dt1`.`a` = (/* select#4 */ select `dt2`.`a` from `dt` `dt2`))) AS `subq` from `test`.`t1`
select (with dt as (select t2.a as a from t2 having t1.a=t2.a limit 1) select * from dt dt1 where dt1.a=(select * from dt as dt2)) as subq from t1;
subq
1
2
# Scope of outer ref in CTE
select (select * from (select t1.a) cte) from t1;
(select * from (select t1.a) cte)
1
2
select (with cte as (select t1.a) select * from cte) from t1;
(with cte as (select t1.a) select * from cte)
1
2
with cte as (select t1.a) select (select * from cte) from t1;
ERROR 42S02: Unknown table 't1' in field list
# NOT IN(subquery using derived), handled with subquery materialization
explain select * from t1
where a not in (select dt.f+1 from (select t2.a as f from t2) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select (`dt`.`f` + 1) from (/* select#3 */ select `test`.`t2`.`a` AS `f` from `test`.`t2`) `dt` where true having true ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on <auto_distinct_key> where ((`test`.`t1`.`a` = `materialized-subquery`.`dt.f+1`)))) is false)
select * from t1
where a not in (select dt.f+1 from (select t2.a as f from t2) dt);
a b
1 NULL
# Now put an outer reference inside derived table:
# subquery is properly seen as correlated and subquery
# materialization is thus not used.
explain select * from t1
where a not in (select dt.f+1 from (select 0*t1.a+t2.a as f from t2) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 Using where
3 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from (/* select#3 */ select ((0 * `test`.`t1`.`a`) + `test`.`t2`.`a`) AS `f` from `test`.`t2`) `dt` where <if>(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = (`dt`.`f` + 1)) or ((`dt`.`f` + 1) is null)), true) having <if>(outer_field_is_not_null, <is_not_null_test>((`dt`.`f` + 1)), true)) is false)
select * from t1
where a not in (select dt.f+1 from (select 0*t1.a+t2.a as f from t2) dt);
a b
1 NULL
# Verify that a non-lateral derived table with an outer
# reference makes the semijoin be correlated and thus blocks
# semijoin-materialization-scan.
create table t11 (a int);
insert into t11
with recursive cte as (select 1 as a union all select a+1 from cte where a<124)
select * from cte;
alter table t11 add index(a);
create table t12 like t11;
analyze table t11,t12;
Table Op Msg_type Msg_text
test.t11 analyze status OK
test.t12 analyze status OK
# No outer ref: mat-scan chosen
explain select
/*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */
* from t11 where a in (select /*+ QB_NAME(subq1) NO_MERGE(dt) */ *
from (select t12.a from t12) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <subquery2> NULL ALL NULL NULL NULL NULL NULL 100.00 Using where
1 PRIMARY t11 NULL ref a a 5 <subquery2>.a 1 100.00 Using index
2 MATERIALIZED <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DERIVED t12 NULL index NULL a 5 NULL 1 100.00 Using index
Warnings:
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) NO_MERGE(`dt`@`subq1`) */ `test`.`t11`.`a` AS `a` from `test`.`t11` semi join ((/* select#3 */ select `test`.`t12`.`a` AS `a` from `test`.`t12`) `dt`) where (`test`.`t11`.`a` = `<subquery2>`.`a`)
# outer ref: mat-scan not chosen
explain select
/*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) */
* from t11 where a in (select /*+ QB_NAME(subq1) NO_MERGE(dt) */ *
from (select t12.a+0*t11.a from t12) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 NULL index a a 5 NULL 124 100.00 Using where; Using index; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 9 test.t11.a 2 100.00 Using where; Using index; Start temporary; End temporary
3 DEPENDENT DERIVED t12 NULL index NULL a 5 NULL 1 100.00 Using index
Warnings:
Note 1276 Field or reference 'test.t11.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`subq1` FIRSTMATCH, LOOSESCAN, DUPSWEEDOUT) NO_MERGE(`dt`@`subq1`) */ `test`.`t11`.`a` AS `a` from `test`.`t11` semi join (lateral (/* select#3 */ select (`test`.`t12`.`a` + (0 * `test`.`t11`.`a`)) AS `t12.a+0*t11.a` from `test`.`t12`) `dt`) where (`test`.`t11`.`a` = `dt`.`t12.a+0*t11.a`)
DROP TABLE t11,t12;
LATERAL
# prevents join buffer if materialized (but not if merged)
explain select dt.a from t1, lateral (select t1.a from t2) dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `dt`.`a` AS `a` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a` from `test`.`t2`) `dt`
# no right join
explain select dt.a from t1 right join lateral (select t1.a from t2) dt on 1;
ERROR HY000: INNER or LEFT JOIN must be used for LATERAL references made by 'dt'
# no bad left join either
explain select dt.a from lateral (select t1.a from t2) dt left join t1 on 1;
ERROR 42S22: Unknown column 't1.a' in 'field list'
# more complex case
explain SELECT * FROM t1
LEFT JOIN
lateral (select t1.a) as dt ON t1.a=dt.a
RIGHT JOIN
lateral (select dt.a) as dt1 ON dt.a=dt1.a;
ERROR HY000: INNER or LEFT JOIN must be used for LATERAL references made by 'dt1'
# LATERAL DT depending on LATERAL DT
explain SELECT * FROM t1
JOIN
lateral (select t1.a) as dt ON t1.a=dt.a
JOIN
lateral (select dt.a) as dt1 ON dt.a=dt1.a;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where; Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using index; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using index
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'dt.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt1`.`a` AS `a` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select `dt`.`a` AS `a`) `dt1` where ((`dt`.`a` = `test`.`t1`.`a`) and (`dt1`.`a` = `test`.`t1`.`a`))
# Placing lateral outer ref in SELECT list then HAVING
select t1.a, dt.a from t1, lateral (select t1.a+t2.a as a from t2) dt;
a a
1 2
1 3
2 3
2 4
select t1.a, dt.a from t1, lateral (select t2.a as a from t2 having t1.a) dt;
a a
1 1
1 2
2 1
2 2
# Inside view
create view v1 as
select t1.a as f1, dt.a as f2
from t1, lateral (select t1.a+t2.a as a from t2) dt;
show create view v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `f1`,`dt`.`a` AS `f2` from (`t1` join lateral (select (`t1`.`a` + `t2`.`a`) AS `a` from `t2`) `dt`) utf8mb4 utf8mb4_0900_ai_ci
select * from v1;
f1 f2
1 2
1 3
2 3
2 4
drop view v1;
# Coverage for various branches in Item_ref::fix_fields
SELECT COUNT(*) FROM t1 GROUP BY t1.a HAVING t1.a IN (SELECT t3.a
FROM t1 AS t3 WHERE t3.b IN (SELECT b FROM t2, lateral (select t1.a) dt));
COUNT(*)
create view v1 as select a, b from t1;
select vq1.b,dt.b from v1 vq1, lateral (select vq1.b) dt;
b b
NULL NULL
NULL NULL
select b from v1 vq1, lateral (select count(*) from v1 vq2 having vq1.b = 3) dt;
b
drop view v1;
SELECT
/*+ SET_VAR(optimizer_switch = 'materialization=off,semijoin=off') */
* FROM t1 AS ta, lateral (select 1 WHERE ta.a IN (SELECT b FROM t2 AS tb WHERE tb.b >= SOME(SELECT SUM(tc.a) as sg FROM t1 as tc GROUP BY tc.b HAVING ta.a=tc.b))) dt;
a b 1
select (select dt.a from (select 1 as a, t2.a as b from t2 having
t1.a) dt where dt.b=t1.a) as subq from t1;
subq
1
1
select (select dt.a from (select 1 as a, 3 as b from t2 having t1.a)
dt where dt.b=t1.a) as subq from t1;
subq
NULL
NULL
# Aggregation in outer context
select (select f from (select max(t1.a) as f) as dt) as g from t1;
g
2
select (select f from lateral (select max(t1.a) as f) as dt) as g from t1;
g
2
# LATERAL doesn't allow an aggregate to resolve to the
# immediate parent (because reading of FROM tables happens
# before aggregation). So it resolves in the derived table, so
# the outer query doesn't produce a single-row result.
select t1.a, f from t1, lateral (select max(t1.a) as f) as dt;
a f
1 1
2 2
# We support CTE inside derived table
select * from t1,
lateral (with qn as (select t1.a) select (select max(a) from qn)) as dt;
a b (select max(a) from qn)
1 NULL 1
2 NULL 2
# Coverage for crash in Item_ident::fix_after_pullout:
# when we merge a derived table contained in a derived table,
# and the merged one contains an outer ref to the top query.
select (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) from t1;
(select * from (select * from (select t1.a from t2) as dt limit 1) dt2)
1
2
# Semijoin containing a correlated derived table, DT must
# become LATERAL
explain select a from t1 where a in (select a from (select t1.a) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 5 test.t1.a 2 100.00 Using index; FirstMatch(t1)
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (lateral (/* select#3 */ select `test`.`t1`.`a` AS `a`) `dt`) where (`dt`.`a` = `test`.`t1`.`a`)
select a from t1 where a in (select a from (select t1.a) dt);
a
1
2
create table t3 as with recursive cte as (select 1 as a union select a+1 from cte where a<20) select * from cte;
analyze table t3;
Table Op Msg_type Msg_text
test.t3 analyze status OK
explain select min(a),max(a) from t3 where a in (select /*+ no_merge() */ a from (select t3.a from t1) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 20 100.00 Using where; Rematerialize (<derived3>)
1 PRIMARY <derived3> NULL ref <auto_key0> <auto_key0> 9 test.t3.a 2 100.00 Using index; FirstMatch(t3)
3 DEPENDENT DERIVED t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t3.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_MERGE(@`select#2`) */ min(`test`.`t3`.`a`) AS `min(a)`,max(`test`.`t3`.`a`) AS `max(a)` from `test`.`t3` semi join (lateral (/* select#3 */ select `test`.`t3`.`a` AS `a` from `test`.`t1`) `dt`) where (`dt`.`a` = `test`.`t3`.`a`)
select min(a),max(a) from t3 where a in (select /*+ no_merge() */ a from (select t3.a from t1) dt);
min(a) max(a)
1 20
drop table t3;
# DT containing a correlated DT which must become LATERAL
explain format=tree select * from t1, lateral (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) dt3;
EXPLAIN
-> Nested loop inner join
-> Invalidate materialized tables (row from t1) (cost=0.45 rows=2)
-> Table scan on t1 (cost=0.45 rows=2)
-> Table scan on dt3
-> Materialize (invalidate on row from t1)
-> Table scan on dt2
-> Materialize
-> Limit: 1 row(s)
-> Table scan on dt
-> Materialize
-> Table scan on t2 (cost=0.45 rows=2)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
explain select * from t1, lateral (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) dt3;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt3`.`a` AS `a` from `test`.`t1` join lateral (/* select#2 */ select `dt2`.`a` AS `a` from (/* select#3 */ select `dt`.`a` AS `a` from (/* select#4 */ select `test`.`t1`.`a` AS `a` from `test`.`t2`) `dt` limit 1) `dt2`) `dt3`
select * from t1, lateral (select * from (select * from (select t1.a from t2) as dt limit 1) dt2) dt3;
a b a
1 NULL 1
2 NULL 2
explain select * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 4 100.00 NULL
2 DEPENDENT DERIVED t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
3 DEPENDENT DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED <derived5> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
5 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`dt4`.`a` AS `a` from `test`.`t1` `t0` join lateral (/* select#2 */ select `dt3`.`a` AS `a` from `test`.`t1` join (/* select#3 */ select `dt2`.`a` AS `a` from (/* select#4 */ select `dt`.`a` AS `a` from (/* select#5 */ select `test`.`t0`.`a` AS `a` from `test`.`t2`) `dt` limit 1) `dt2`) `dt3`) `dt4`
select * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
a b a
1 NULL 1
1 NULL 1
2 NULL 2
2 NULL 2
explain select /*+ no_merge() */ * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 4 100.00 NULL
2 DEPENDENT DERIVED t1 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
3 DEPENDENT DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED <derived5> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
5 DEPENDENT DERIVED t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #5 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_MERGE(@`select#1`) */ `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`dt4`.`a` AS `a` from `test`.`t1` `t0` join lateral (/* select#2 */ select `dt3`.`a` AS `a` from `test`.`t1` join (/* select#3 */ select `dt2`.`a` AS `a` from (/* select#4 */ select `dt`.`a` AS `a` from (/* select#5 */ select `test`.`t0`.`a` AS `a` from `test`.`t2`) `dt` limit 1) `dt2`) `dt3`) `dt4`
select /*+ no_merge() */ * from t1 as t0,
lateral
(select dt3.* from t1, lateral (select * from (select * from (select t0.a
from t2) as dt limit 1) dt2) dt3) dt4;
a b a
1 NULL 1
1 NULL 1
2 NULL 2
2 NULL 2
explain select * from t1, lateral (select * from (select 42) t1, (select t1.a) dt2) dt3;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED <derived3> NULL system NULL NULL NULL NULL 1 100.00 NULL
2 DEPENDENT DERIVED <derived4> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
4 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #4 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt3`.`42` AS `42`,`dt3`.`a` AS `a` from `test`.`t1` join lateral (/* select#2 */ select '42' AS `42`,`dt2`.`a` AS `a` from (/* select#4 */ select `test`.`t1`.`a` AS `a`) `dt2`) `dt3`
select * from t1, lateral (select * from (select 42) t1, (select t1.a) dt2) dt3;
a b 42 a
1 NULL 42 1
2 NULL 42 2
without semijoin: index_subquery needs to re-materialize
explain select a from t1 where a in (select /*+ no_semijoin() */ a from (select t1.a) dt);
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Using where
2 DEPENDENT SUBQUERY <derived3> NULL index_subquery <auto_key0> <auto_key0> 5 func 2 100.00 Using index
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select /*+ NO_SEMIJOIN(@`select#2`) */ `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in dt on <auto_key0>)))
select a from t1 where a in (select /*+ no_semijoin() */ a from (select t1.a) dt);
a
1
2
select a from t1 where a in (with cte as (select t1.a)
select /*+ no_semijoin() */ a from cte);
a
1
2
# Count rematerializations
# In all three plans, handler_write is 2, showing that we
# rematerialize only when necessary (when row of t1 changes)
explain select straight_join * from t1, t2, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select straight_join `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t1` join `test`.`t2` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select straight_join * from t1, t2, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 1
2 NULL 1 NULL 2
2 NULL 2 NULL 2
# when a row of t1 produces two rows of t2 passed to "dt",
# it still makes one materialization.
show status like "handler_write";
Variable_name Value
Handler_write 2
explain select straight_join * from t1, lateral (select t1.a) as dt, t2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select straight_join `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join `test`.`t2`
flush status;
select straight_join * from t1, lateral (select t1.a) as dt, t2;
a b a a b
1 NULL 1 1 NULL
1 NULL 1 2 NULL
2 NULL 2 1 NULL
2 NULL 2 2 NULL
show status like "handler_write";
Variable_name Value
Handler_write 2
explain select straight_join * from t2, t1, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>); Using join buffer (Block Nested Loop)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select straight_join `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select straight_join * from t2, t1, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 2
2 NULL 1 NULL 1
2 NULL 2 NULL 2
# Due to join buffer, order t2-t1 produces rows as a
# non-buffered t1-t2 plan: t1 buffers all rows of t2, then for
# each row of t1 it's joined to all rows of t2 and passed to t2;
# when a row of t1 produces two rows of t2 passed to "dt",
# it still makes one materialization.
show status like "handler_write";
Variable_name Value
Handler_write 2
# Let the planner find the best plan.
# It doesn't work so well, because of
# optimizer_prune_level=1 (see bug#28629788): order specified by
# the user is sorted by number of rows, which leaves it
# unchanged (Card(t1)=Card(t2)=Card(dt)); then it is the first
# explored plan so it's explored in full, and later t1-dt is rejected as
# more expensive than t1-t2. Whereas if t1-dt had been explored
# deeper, we'd see t1-dt-t2 is actually the cheapest, because
# it reads dt the least number of times (and dt has a high read
# cost because Temptable::scan_time() is incredibly high but
# that's another issue; see bug#28631100).
# t2 cannot use join buffering as between "dt" and its
# dependency t1: join buffering would interlace rows of t1
# thus cause more rematerializations.
explain select * from t1, t2, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t1` join `test`.`t2` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select * from t1, t2, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 1
2 NULL 1 NULL 2
2 NULL 2 NULL 2
show status like "handler_write";
Variable_name Value
Handler_write 2
# This one finds the best plan. Yes we simply swapped tables in the query,
# and it yields a different plan. This is because the order specified by
# the user is sorted by number of rows, which leaves it
# unchanged (Card(t1)=Card(t2)=Card(dt), then it is the first
# explored plan so it's explored in full and so is never pruned by
# prune_level=1, and it is the best plan. Best as: it reads
# "dt" less, and t2 uses join buffering (which is ok as it's
# after "dt").
# If prune_level=0, all 3 variants here produce this plan.
explain select * from t1, lateral (select t1.a) as dt, t2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join `test`.`t2`
flush status;
select * from t1, lateral (select t1.a) as dt, t2;
a b a a b
1 NULL 1 1 NULL
1 NULL 1 2 NULL
2 NULL 2 1 NULL
2 NULL 2 2 NULL
show status like "handler_write";
Variable_name Value
Handler_write 2
# This one is intermediate: t1 uses join buffer (good), but
# "dt" is last (bad, as it has high scan cost).
explain select * from t2, t1, lateral (select t1.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>); Using join buffer (Block Nested Loop)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt`
flush status;
select * from t2, t1, lateral (select t1.a) as dt;
a b a b a
1 NULL 1 NULL 1
1 NULL 2 NULL 2
2 NULL 1 NULL 1
2 NULL 2 NULL 2
show status like "handler_write";
Variable_name Value
Handler_write 2
# Show the trace of planning of lateral derived tables
explain select * from t1, lateral (select t1.a from t2 as t3, t2 as t4) as dt, t2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 4 100.00 NULL
2 DEPENDENT DERIVED t3 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED t4 NULL ALL NULL NULL NULL NULL 2 100.00 Using join buffer (Block Nested Loop)
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a` from `test`.`t2` `t3` join `test`.`t2` `t4`) `dt` join `test`.`t2`
select trace from information_schema.optimizer_trace;
trace
{
"steps": [
{
"join_preparation": {
"select#": 1,
"steps": [
{
"join_preparation": {
"select#": 2,
"steps": [
{
"expanded_query": "/* select#2 */ select `t1`.`a` AS `a` from `t2` `t3` join `t2` `t4`"
}
]
}
},
{
"derived": {
"table": " `dt`",
"select#": 2,
"materialized": true
}
},
{
"expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b`,`dt`.`a` AS `a`,`t2`.`a` AS `a`,`t2`.`b` AS `b` from `t1` join lateral (/* select#2 */ select `t1`.`a` AS `a` from `t2` `t3` join `t2` `t4`) `dt` join `t2`"
}
]
}
},
{
"join_optimization": {
"select#": 1,
"steps": [
{
"join_optimization": {
"select#": 2,
"steps": [
{
"table_dependencies": [
{
"table": "`t2` `t3`",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": [
]
},
{
"table": "`t2` `t4`",
"row_may_be_null": false,
"map_bit": 1,
"depends_on_map_bits": [
]
}
]
},
{
"rows_estimation": [
{
"table": "`t2` `t3`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
},
{
"table": "`t2` `t4`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`t2` `t3`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"rest_of_plan": [
{
"plan_prefix": [
"`t2` `t3`"
],
"table": "`t2` `t4`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"using_join_cache": true,
"buffers_needed": 1,
"resulting_rows": 2,
"cost": 0.65,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 4,
"cost_for_plan": 1.1,
"chosen": true
}
]
},
{
"plan_prefix": [
],
"table": "`t2` `t4`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"pruned_by_heuristic": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": null,
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`t2` `t3`",
"attached": null
},
{
"table": "`t2` `t4`",
"attached": null
}
]
}
},
{
"finalizing_table_conditions": [
]
},
{
"refine_plan": [
{
"table": "`t2` `t3`"
},
{
"table": "`t2` `t4`"
}
]
}
]
}
},
{
"table_dependencies": [
{
"table": "`t1`",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": [
]
},
{
"table": " `dt`",
"row_may_be_null": false,
"map_bit": 1,
"depends_on_map_bits": [
0
]
},
{
"table": "`t2`",
"row_may_be_null": false,
"map_bit": 2,
"depends_on_map_bits": [
]
}
]
},
{
"rows_estimation": [
{
"table": "`t1`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
},
{
"table": " `dt`",
"table_scan": {
"rows": 4,
"cost": 2.55
}
},
{
"table": "`t2`",
"table_scan": {
"rows": 2,
"cost": 0.25
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`t1`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"filtering_effect": [
],
"final_filtering_effect": 1,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"rest_of_plan": [
{
"plan_prefix": [
"`t1`"
],
"table": "`t2`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.9,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 4,
"cost_for_plan": 1.35,
"rest_of_plan": [
{
"plan_prefix": [
"`t1`",
"`t2`"
],
"table": " `dt`",
"best_access_path": {
"considered_access_paths": [
{
"lateral_materialization": {
"cost_for_one_run_of_inner_query": 1.099,
"cost_for_writing_to_tmp_table": 0.4,
"count_of_runs": 2,
"total_cost": 2.998,
"cost_per_read": 0.7495
}
},
{
"rows_to_scan": 4,
"access_type": "scan",
"resulting_rows": 4,
"cost": 11.8,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 16,
"cost_for_plan": 13.899,
"chosen": true
}
]
},
{
"plan_prefix": [
"`t1`"
],
"table": " `dt`",
"best_access_path": {
"considered_access_paths": [
{
"lateral_materialization": {
"cost_for_one_run_of_inner_query": 1.099,
"cost_for_writing_to_tmp_table": 0.4,
"count_of_runs": 2,
"total_cost": 2.998,
"cost_per_read": 1.499
}
},
{
"rows_to_scan": 4,
"access_type": "scan",
"resulting_rows": 4,
"cost": 5.9,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 8,
"cost_for_plan": 7.849,
"pruned_by_heuristic": true
}
]
},
{
"plan_prefix": [
],
"table": "`t2`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 2,
"access_type": "scan",
"resulting_rows": 2,
"cost": 0.45,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 2,
"cost_for_plan": 0.45,
"pruned_by_heuristic": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": null,
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`t1`",
"attached": null
},
{
"table": "`t2`",
"attached": null
},
{
"table": " `dt`",
"attached": null
}
]
}
},
{
"finalizing_table_conditions": [
]
},
{
"refine_plan": [
{
"table": "`t1`"
},
{
"table": "`t2`"
},
{
"table": " `dt`",
"rematerialized_for_each_row_of": "t1"
}
]
}
]
}
},
{
"join_explain": {
"select#": 1,
"steps": [
{
"creating_tmp_table": {
"tmp_table_info": {
"table": " `dt`",
"in_plan_at_position": 2,
"columns": 1,
"row_length": 5,
"key_length": 0,
"unique_constraint": false,
"makes_grouped_rows": false,
"cannot_insert_duplicates": false,
"location": "TempTable"
}
}
},
{
"join_explain": {
"select#": 2,
"steps": [
]
}
}
]
}
}
]
}
# LDT depending on const table only
create table t3(a int) engine=innodb;
insert into t3 values(3);
analyze table t3;
Table Op Msg_type Msg_text
test.t3 analyze status OK
explain select * from t3, lateral (select t3.a+1) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 NULL ALL NULL NULL NULL NULL 1 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t3.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`dt`.`t3.a+1` AS `t3.a+1` from `test`.`t3` join lateral (/* select#2 */ select (`test`.`t3`.`a` + 1) AS `t3.a+1`) `dt`
select * from t3, lateral (select t3.a+1) as dt;
a t3.a+1
3 4
drop table t3;
# Two LDTs depending on different tables
explain select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t2.a) as dt2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived3>)
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t2.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt2`.`a` AS `a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select `test`.`t2`.`a` AS `a`) `dt2`
select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t2.a) as dt2;
a b a b a a
1 NULL 1 NULL 1 1
1 NULL 2 NULL 2 1
2 NULL 1 NULL 1 2
2 NULL 2 NULL 2 2
# Two LDTs depending on one same table
explain select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t1.a+1) as dt2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>,<derived3>); Using join buffer (Block Nested Loop)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY <derived3> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
3 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt2`.`t1.a+1` AS `t1.a+1` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select (`test`.`t1`.`a` + 1) AS `t1.a+1`) `dt2`
explain format=json select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t1.a+1) as dt2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "34.10"
},
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 2,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.20",
"prefix_cost": "0.45",
"data_read_per_join": "32"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 4,
"filtered": "100.00",
"rematerialize": "dt,dt2",
"using_join_buffer": "Block Nested Loop",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.40",
"prefix_cost": "1.10",
"data_read_per_join": "64"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "dt",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 8,
"filtered": "100.00",
"cost_info": {
"read_cost": "10.30",
"eval_cost": "0.80",
"prefix_cost": "12.20",
"data_read_per_join": "128"
},
"used_columns": [
"a"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": true,
"cacheable": true,
"query_block": {
"select_id": 2,
"message": "No tables used"
}
}
}
},
{
"table": {
"table_name": "dt2",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 16,
"filtered": "100.00",
"cost_info": {
"read_cost": "20.30",
"eval_cost": "1.60",
"prefix_cost": "34.10",
"data_read_per_join": "256"
},
"used_columns": [
"t1.a+1"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": true,
"cacheable": true,
"query_block": {
"select_id": 3,
"message": "No tables used"
}
}
}
}
]
}
}
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`a` AS `a`,`dt2`.`t1.a+1` AS `t1.a+1` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select `test`.`t1`.`a` AS `a`) `dt` join lateral (/* select#3 */ select (`test`.`t1`.`a` + 1) AS `t1.a+1`) `dt2`
select * from t2, t1, lateral (select t1.a) as dt,
lateral (select t1.a+1) as dt2;
a b a b a t1.a+1
1 NULL 1 NULL 1 2
1 NULL 2 NULL 2 3
2 NULL 1 NULL 1 2
2 NULL 2 NULL 2 3
# One LDT depending on two tables. The "rematerialize" tag is
# properly added to the 2nd dependency only.
explain select * from t2, t1, lateral (select t1.a+t2.a) as dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 NULL ALL NULL NULL NULL NULL 2 100.00 NULL
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t2.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`t1.a+t2.a` AS `t1.a+t2.a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select (`test`.`t1`.`a` + `test`.`t2`.`a`) AS `t1.a+t2.a`) `dt`
explain format=json select * from t2, t1, lateral (select t1.a+t2.a) as dt;
EXPLAIN
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "12.45"
},
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 2,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.20",
"prefix_cost": "0.45",
"data_read_per_join": "32"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 4,
"filtered": "100.00",
"rematerialize": "dt",
"cost_info": {
"read_cost": "0.50",
"eval_cost": "0.40",
"prefix_cost": "1.35",
"data_read_per_join": "64"
},
"used_columns": [
"a",
"b"
]
}
},
{
"table": {
"table_name": "dt",
"access_type": "ALL",
"rows_examined_per_scan": 2,
"rows_produced_per_join": 8,
"filtered": "100.00",
"cost_info": {
"read_cost": "10.30",
"eval_cost": "0.80",
"prefix_cost": "12.45",
"data_read_per_join": "128"
},
"used_columns": [
"t1.a+t2.a"
],
"materialized_from_subquery": {
"using_temporary_table": true,
"dependent": true,
"cacheable": true,
"query_block": {
"select_id": 2,
"message": "No tables used"
}
}
}
}
]
}
}
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 'test.t2.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`t1.a+t2.a` AS `t1.a+t2.a` from `test`.`t2` join `test`.`t1` join lateral (/* select#2 */ select (`test`.`t1`.`a` + `test`.`t2`.`a`) AS `t1.a+t2.a`) `dt`
select * from t2, t1, lateral (select t1.a+t2.a) as dt;
a b a b t1.a+t2.a
1 NULL 1 NULL 2
1 NULL 2 NULL 3
2 NULL 1 NULL 3
2 NULL 2 NULL 4
select json_extract(trace,"$.steps[*].join_optimization.steps[*].refine_plan") from information_schema.optimizer_trace;
json_extract(trace,"$.steps[*].join_optimization.steps[*].refine_plan")
[[{"table": "`t2`"}, {"table": "`t1`"}, {"table": " `dt`", "rematerialized_for_each_row_of": "t1"}]]
# Test when a dependency of LDT uses BKA: BKA code must
# refresh LDT's content when it provides a row.
set @old_opt_switch=@@optimizer_switch;
set @@optimizer_switch="batched_key_access=on,mrr_cost_based=off";
CREATE TABLE t11 (t11a int, t11b int);
INSERT INTO t11 VALUES (99, NULL),(99, 3),(99,0);
CREATE TABLE t12 (t12a int, t12b int, KEY idx (t12b));
INSERT INTO t12 VALUES (100,0),(150,200),(999, 0),(999, NULL);
ANALYZE TABLE t11,t12;
Table Op Msg_type Msg_text
test.t11 analyze status OK
test.t12 analyze status OK
explain SELECT * FROM t11 LEFT JOIN t12 force index (idx) ON t12.t12b = t11.t11b
JOIN LATERAL (SELECT t12a) dt;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t11 NULL ALL NULL NULL NULL NULL 3 100.00 NULL
1 PRIMARY t12 NULL ref idx idx 5 test.t11.t11b 1 100.00 Rematerialize (<derived2>); Using join buffer (Batched Key Access)
1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 2 100.00 NULL
2 DEPENDENT DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1276 Field or reference 'test.t12.t12a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t11`.`t11a` AS `t11a`,`test`.`t11`.`t11b` AS `t11b`,`test`.`t12`.`t12a` AS `t12a`,`test`.`t12`.`t12b` AS `t12b`,`dt`.`t12a` AS `t12a` from `test`.`t11` left join `test`.`t12` FORCE INDEX (`idx`) on((`test`.`t12`.`t12b` = `test`.`t11`.`t11b`)) join lateral (/* select#2 */ select `test`.`t12`.`t12a` AS `t12a`) `dt` where true
flush status;
SELECT * FROM t11 LEFT JOIN t12 force index (idx) ON t12.t12b = t11.t11b
JOIN LATERAL (SELECT t12a) dt;
t11a t11b t12a t12b t12a
99 0 100 0 100
99 0 999 0 999
99 NULL NULL NULL NULL
99 3 NULL NULL NULL
show status like "handler_write";
Variable_name Value
Handler_write 3
DROP TABLE t11,t12;
set @@optimizer_switch=@old_opt_switch;
# Test that with an auto_key on the lateral DT, the index is
# properly emptied and re-filled when re-materializing.
# If index weren't emptied, we'd see too many "11" matches for 2nd
# row of t1; and if not re-filled, we'd see no matches for that.
create table t3 (a int, b int);
insert into t3 values(1, 10), (1, 11), (2, 10), (2, 11);
analyze table t3;
Table Op Msg_type Msg_text
test.t3 analyze status OK
# Note the auto_key with "Using index", to test the index as
# much as possible.
explain select * from t1, lateral (select t3.b from t3 where t3.a=t1.a) dt
where dt.b=t1.a+9;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 2 100.00 Rematerialize (<derived2>)
1 PRIMARY <derived2> NULL ref <auto_key0> <auto_key0> 5 func 2 100.00 Using where; Using index
2 DEPENDENT DERIVED t3 NULL ALL NULL NULL NULL NULL 4 25.00 Using where
Warnings:
Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`dt`.`b` AS `b` from `test`.`t1` join lateral (/* select#2 */ select `test`.`t3`.`b` AS `b` from `test`.`t3` where (`test`.`t3`.`a` = `test`.`t1`.`a`)) `dt` where (`dt`.`b` = (`test`.`t1`.`a` + 9))
select * from t1, lateral (select t3.b from t3 where t3.a=t1.a) dt
where dt.b=t1.a+9;
a b b
1 NULL 10
2 NULL 11
drop table t3;
set optimizer_switch='derived_merge=off';
# Reserved word
create table lateral(a int);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'lateral(a int)' at line 1
drop table t1,t2;
#
# Bug#28723670 RECENT REGRESSION: CRASH/ASSERTION IN FIND_FIELD_IN_TABLE_REF
#
CREATE TABLE t(x INT);
# Don't search for 'y' in top SELECT
SELECT 1 FROM
(SELECT 1 FROM (SELECT (SELECT y FROM t) FROM t) AS a) AS b;
ERROR 42S22: Unknown column 'y' in 'field list'
DROP TABLE t;
#
# Bug#28976533 ASSERTION `JOIN->BEST_READ < DOUBLE(1.79769313486231570814527423731704357E+308L)
#
CREATE TABLE bb (
pk INTEGER AUTO_INCREMENT,
col_int INTEGER ,
col_int_key INTEGER ,
col_time_key TIME ,
col_time TIME ,
col_datetime_key DATETIME ,
col_datetime DATETIME ,
col_varchar_key VARCHAR(20) ,
col_varchar VARCHAR(20) ,
PRIMARY KEY (pk DESC),
KEY (col_time_key),
KEY (col_time_key DESC)
);
SET SQL_MODE='';
EXPLAIN SELECT
grandparent1.col_varchar_key AS g1 FROM bb AS grandparent1
LEFT JOIN bb AS grandparent2 USING ( col_time )
WHERE grandparent1.col_int_key IN
(
WITH qn AS (
SELECT parent1.col_int AS p1
FROM bb AS parent1 LEFT JOIN bb AS parent2 USING ( col_varchar )
WHERE parent1.col_varchar_key IN
(
WITH qn1 AS (
SELECT DISTINCT child1.col_varchar_key AS C1
FROM bb AS child1 LEFT JOIN bb AS child2
ON child1.col_varchar_key <= child2.col_varchar
WHERE child1.col_time > grandparent1.col_datetime
)
SELECT * FROM qn1
)
AND parent1.col_time_key BETWEEN '2008-03-18' AND
'2004-11-14'
)
SELECT /*+ MERGE(qn) */ * FROM qn
)
GROUP BY grandparent1.col_int;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
5 DEPENDENT DERIVED child1 NULL ALL NULL NULL NULL NULL 1 100.00 Using where; Using temporary
5 DEPENDENT DERIVED child2 NULL ALL NULL NULL NULL NULL 1 100.00 Using where; Distinct; Using join buffer (Block Nested Loop)
Warnings:
Note 1276 Field or reference 'test.grandparent1.col_datetime' of SELECT #5 was resolved in SELECT #1
Warning 1292 Incorrect time value: '2008-03-18' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2004-11-14' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2008-03-18' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2008-03-18' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2004-11-14' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2004-11-14' for column 'col_time_key' at row 1
Note 1003 /* select#1 */ select /*+ MERGE(`qn`@`select#2`) */ `test`.`grandparent1`.`col_varchar_key` AS `g1` from `test`.`bb` `grandparent1` left join `test`.`bb` `grandparent2` on(multiple equal(`test`.`grandparent1`.`col_time`, `test`.`grandparent2`.`col_time`)) semi join (`test`.`bb` `parent1` left join `test`.`bb` `parent2` on((`test`.`parent1`.`col_varchar` = `test`.`parent2`.`col_varchar`)) join `qn1`) where ((`test`.`parent1`.`col_time_key` between '2008-03-18' and '2004-11-14') and multiple equal(`test`.`grandparent1`.`col_int_key`, `test`.`parent1`.`col_int`) and multiple equal(`test`.`parent1`.`col_varchar_key`, `qn1`.`C1`)) group by `test`.`grandparent1`.`col_int`
SELECT
grandparent1.col_varchar_key AS g1 FROM bb AS grandparent1
LEFT JOIN bb AS grandparent2 USING ( col_time )
WHERE grandparent1.col_int_key IN
(
WITH qn AS (
SELECT parent1.col_int AS p1
FROM bb AS parent1 LEFT JOIN bb AS parent2 USING ( col_varchar )
WHERE parent1.col_varchar_key IN
(
WITH qn1 AS (
SELECT DISTINCT child1.col_varchar_key AS C1
FROM bb AS child1 LEFT JOIN bb AS child2
ON child1.col_varchar_key <= child2.col_varchar
WHERE child1.col_time > grandparent1.col_datetime
)
SELECT * FROM qn1
)
AND parent1.col_time_key BETWEEN '2008-03-18' AND
'2004-11-14'
)
SELECT /*+ MERGE(qn) */ * FROM qn
)
GROUP BY grandparent1.col_int;
g1
Warnings:
Warning 1292 Incorrect time value: '2008-03-18' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2004-11-14' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2008-03-18' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2008-03-18' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2004-11-14' for column 'col_time_key' at row 1
Warning 1292 Incorrect time value: '2004-11-14' for column 'col_time_key' at row 1
DROP TABLE bb;
SET SQL_MODE=DEFAULT;
#
# Bug #29268512: ASSERTION FAILED: INITED == NONE INTERMITTENTLY
#
CREATE TABLE t1 (
f1 integer
);
INSERT INTO t1 VALUES (0),(1);
CREATE TABLE t2 (
f2 integer
);
SELECT * FROM t1, LATERAL ( SELECT MAX(1) FROM t2 GROUP BY t1.f1 ) AS l1;
f1 MAX(1)
DROP TABLE t1, t2;
#
# Bug #29334082: Still crashing in actual_key_parts() / assert inited == INDEX
#
CREATE TABLE t1 ( f1 INTEGER );
CREATE TABLE t2 ( f2 LONGBLOB );
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES ('abc'),('def');
SELECT STD(0) FROM t2, LATERAL ( SELECT f1 FROM t1 GROUP BY f2,f1 ) AS d1;
STD(0)
0
DROP TABLE t1, t2;
#
# Bug#28954838 ASSERTION `(REMAINING_TABLES_AFTER != 0) || ((CUR_EMBEDDING_MAP == 0) && (JOIN->
#
CREATE TABLE t1 (
pk INTEGER,
col_int INT not null,
col_int_key INT not null,
col_time_gckey TIME,
col_varchar VARCHAR(20) not null,
col_varchar_key VARCHAR(15) not null
);
CREATE TABLE t2 (
pk INTEGER,
col_int INT not null,
col_varchar VARCHAR(20) not null,
col_varchar_key VARCHAR(15) not null
);
SET OPTIMIZER_SWITCH='derived_merge=off';
SELECT table1.col_varchar_key AS field1,
table2.col_time_gckey AS field2
FROM t2 AS table1 STRAIGHT_JOIN t1 AS table2
ON table2.col_varchar_key = table1.col_varchar_key
WHERE table2.col_int_key IN
(WITH qn AS
(SELECT sq1_t1.col_int AS sq1_field1
FROM t2 AS sq1_t1
WHERE sq1_t1.col_varchar_key = table2.col_varchar OR
EXISTS (WITH qn1 AS
(SELECT c_sq1_t1.col_int_key AS c_sq1_field1
FROM t1 AS c_sq1_t1
WHERE c_sq1_t1.col_varchar_key > sq1_t1.col_varchar OR
c_sq1_t1.col_int <> c_sq1_t1.pk
)
SELECT * FROM qn1
)
)
SELECT * FROM qn
) AND
EXISTS (WITH qn AS
(SELECT sq2_t1.col_varchar AS sq2_field1
FROM t1 AS sq2_t1 STRAIGHT_JOIN
t2 AS sq2_t2 INNER JOIN t1 AS sq2_t3
ON sq2_t3.col_varchar = sq2_t2.col_varchar_key
ON sq2_t3.col_int = sq2_t2.pk
)
SELECT * FROM qn
) AND
table2.col_varchar_key <> 'j';
field1 field2
SET OPTIMIZER_SWITCH=DEFAULT;
DROP TABLE t1,t2;
#
# Bug#28955358 VIRTUAL LONGLONG FIELD_NEWDATE::VAL_DATE_TEMPORAL(): ASSERTION `!TABLE || (!TAB
#
CREATE TABLE t1 (
pk INTEGER, col_int_key INTEGER NOT NULL,
col_date_key DATE NOT NULL, col_datetime DATETIME NOT NULL
);
INSERT INTO t1 VALUES (0, 0, '2006-07-18', '2001-09-06 02:13:59.021506');
SELECT /*+ no_merge() */ outr.pk AS x
FROM ( SELECT * FROM t1 ) AS outr
WHERE outr.col_int_key IN
( SELECT /*+ no_merge() no_semijoin() */ 2
FROM (SELECT 1 AS x FROM t1 AS innr WHERE outr.col_date_key ) AS
qn )
ORDER BY outr.col_datetime;
x
SELECT /*+ no_merge() */ outr.pk AS x
FROM ( SELECT * FROM t1 ) AS outr
WHERE outr.col_int_key IN
( SELECT /*+ no_merge() no_semijoin() */ id
FROM JSON_TABLE( IF(outr.col_date_key<>NOW(),
'[{"a":"3"},{"a":2},{"b":1},{"a":0}]',
'') ,
'$[*]' columns (id for ordinality,
jpath varchar(100) path '$.a',
jexst int exists path '$.b') ) AS
qn )
ORDER BY outr.col_datetime;
x
DROP TABLE t1;
CREATE TABLE t1(pk INT PRIMARY KEY, a INT);
EXPLAIN SELECT pk FROM t1 GROUP BY a;
ERROR 42000: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.t1.pk' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
EXPLAIN SELECT (SELECT pk FROM (SELECT t1.pk) dt) FROM t1 GROUP BY a;
ERROR 42000: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.t1.pk' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
DROP TABLE t1;
#
# Bug#28960857 ASSERTION FAILED: !TR->DERIVED_WHERE_COND || TR->DERIVED_WHERE_COND->FIXED
# Bug#28960789 ASSERTION FAILED: TRANSL->ITEM->FIXED,
#
CREATE TABLE t0007 (
c0008 date NOT NULL,
c0009 char(234) NOT NULL
);
CREATE TABLE t0008 (
c0005 tinytext NOT NULL
);
CREATE TABLE t0009 (
c0000 time NOT NULL
);
SET SQL_MODE=0;
SELECT (SELECT t0007.c0009 FROM (SELECT t0007.c0008 AS c0003
FROM t0009 ) AS t0005 ) FROM t0007
GROUP BY -23;
(SELECT t0007.c0009 FROM (SELECT t0007.c0008 AS c0003
FROM t0009 ) AS t0005 )
SELECT (SELECT c0009
FROM (SELECT 1 AS c0003
FROM t0009 INNER JOIN t0008
ON t0008.c0005
WHERE t0007.c0008
) AS t0005
GROUP BY c0008
),
COUNT(c0009)
FROM t0007
GROUP BY 1, 1;
(SELECT c0009
FROM (SELECT 1 AS c0003
FROM t0009 INNER JOIN t0008
ON t0008.c0005
WHERE t0007.c0008
) AS t0005
GROUP BY c0008
) COUNT(c0009)
DROP TABLE t0007, t0008, t0009;
SET SQL_MODE=DEFAULT;
#
# Bug #29514504: WRONG RESULT WITH CORRELATED LATERAL JOIN
#
CREATE TABLE t1 (id INTEGER);
CREATE TABLE t2 (id INTEGER);
INSERT INTO t1 VALUES (10), (20), (30);
INSERT INTO t2 VALUES (20), (20);
SELECT * FROM t1 JOIN LATERAL (
SELECT GROUP_CONCAT(t.id) AS c FROM t2 t WHERE (t.id = t1.id)
) d0 ON (1);
id c
10 NULL
20 20,20
30 NULL
DROP TABLE t1, t2;
#
# Bug #30110851: SUBQUERY INVOLVES COUNT() AGGREGATE FUNCTION PERFORMANCE REGRESSION
#
CREATE TABLE t1 ( f1 INTEGER NOT NULL, f2 INTEGER NOT NULL );
CREATE TABLE t2 ( f1 INTEGER NOT NULL, f2 INTEGER NOT NULL );
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1;
CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT ( SELECT f2 FROM v1 WHERE v1.f1 = t2.f1 ) AS f3 FROM t2;
EXPLAIN FORMAT=TREE SELECT * FROM v2 WHERE f3 = 3;
EXPLAIN
-> Index lookup on v2 using <auto_key0> (f3=3)
-> Materialize
-> Table scan on t2 (cost=0.35 rows=1)
-> Select #3 (subquery in projection; dependent)
-> Index lookup on v1 using <auto_key0> (f1=t2.f1)
-> Materialize
-> Table scan on t1 (cost=0.35 rows=1)
Warnings:
Note 1276 Field or reference 'test.t2.f1' of SELECT #3 was resolved in SELECT #2
DROP TABLE t1, t2;
DROP VIEW v1, v2;