|
Thanks a lot!
Reproducible on MariaDB 5.5-10.4 with optimizer_switch='materialization=on'.
CREATE TABLE t1 (id int, a varchar(50), b int);
|
INSERT INTO t1 VALUES (1, 'mrs', 2),(2, 'joe', 2), (3, 'paul', 1),(4, 'art', 1);
|
|
CREATE TABLE t2 (id int, a varchar(50), x int);
|
INSERT INTO t2 VALUES(1, 'grand', 1),(2, 'average', 1),(3, 'serf', 0);
|
|
CREATE TABLE t3 (d1 date, d2 date, t1_id int, t2_id int );
|
INSERT INTO t3 VALUES ('1972-01-01','1988-12-31', 3, 1),('1972-01-01','1988-12-31', 4, 1),('1972-01-01','1988-12-31', 1, 2),('1972-01-01','1988-12-31', 2, 3);
|
|
CREATE TABLE t4 ( id int, a varchar(50) );
|
INSERT INTO t4 VALUES (1, 'songwriter'),(2, 'song character');
|
|
delimiter $$;
|
create function f1(who int, dt date) returns int
|
begin
|
declare result int;
|
select t2_id into result from t3 where dt>=d1 and dt<=d2 and t1_id=who;
|
return result;
|
end$$
|
delimiter ;$$
|
|
select * from t1
|
left join t4 on t1.b = t4.id
|
where f1(t1.id, '1980-01-01') in (select id from t2 where x=1);
|
|
drop table t1,t2,t3,t4;
|
drop function f1;
|
|
MariaDB [test]> select * from t1
|
-> left join t4 on t1.b = t4.id
|
-> where f1(t1.id, '1980-01-01') in (select id from t2 where x=1);
|
Empty set (0.01 sec)
|
|
MariaDB [test]> set optimizer_switch='materialization=off';
|
Query OK, 0 rows affected (0.00 sec)
|
|
MariaDB [test]> select * from t1 left join t4 on t1.b = t4.id where f1(t1.id, '1980-01-01') in (select id from t2 where x=1);+------+------+------+------+----------------+
|
| id | a | b | id | a |
|
+------+------+------+------+----------------+
|
| 3 | paul | 1 | 1 | songwriter |
|
| 4 | art | 1 | 1 | songwriter |
|
| 1 | mrs | 2 | 2 | song character |
|
+------+------+------+------+----------------+
|
3 rows in set (0.01 sec)
|
|
MariaDB [test]> explain extended
|
-> select * from t1
|
-> left join t4 on t1.b = t4.id
|
-> where f1(t1.id, '1980-01-01') in (select id from t2 where x=1);
|
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+----------+-------------------------------------------------+
|
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+----------+-------------------------------------------------+
|
| 1 | PRIMARY | t1 | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | |
|
| 1 | PRIMARY | <subquery2> | eq_ref | distinct_key | distinct_key | 4 | func | 1 | 100.00 | Using where |
|
| 1 | PRIMARY | t4 | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Using where; Using join buffer (flat, BNL join) |
|
| 2 | MATERIALIZED | t2 | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | Using where |
|
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+----------+-------------------------------------------------+
|
4 rows in set, 1 warning (0.00 sec)
|
|
Note (Code 1003): select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t4`.`id` AS `id`,`test`.`t4`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) left join `test`.`t4` on(`test`.`t4`.`id` = `test`.`t1`.`b`) where `test`.`t2`.`x` = 1 and `f1`(`test`.`t1`.`id`,'1980-01-01') = `test`.`t2`.`id`
|
|
mysql> select * from t1
|
-> left join t4 on t1.b = t4.id
|
-> where f1(t1.id, '1980-01-01') in (select id from t2 where x=1);
|
+------+------+------+------+----------------+
|
| id | a | b | id | a |
|
+------+------+------+------+----------------+
|
| 3 | paul | 1 | 1 | songwriter |
|
| 4 | art | 1 | 1 | songwriter |
|
| 1 | mrs | 2 | 2 | song character |
|
+------+------+------+------+----------------+
|
3 rows in set (0.00 sec)
|
|
|
The results of my analysis:
The output of EXPLAIN EXTENDED is
MariaDB [test]> explain extended select * from t1
|
-> left join t4 on t1.b = t4.id
|
-> where f1(t1.id, '1980-01-01') in (select id from t2 where x=1);
|
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+----------+-------------------------------------------------+
|
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+----------+-------------------------------------------------+
|
| 1 | PRIMARY | t1 | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | |
|
| 1 | PRIMARY | <subquery2> | eq_ref | distinct_key | distinct_key | 4 | func | 1 | 100.00 | Using where |
|
| 1 | PRIMARY | t4 | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Using where; Using join buffer (flat, BNL join) |
|
| 2 | MATERIALIZED | t2 | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | Using where |
|
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+----------+-------------------------------------------------+
|
MariaDB [test]> show warnings;
|
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
| Level | Code | Message |
|
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
| Note | 1003 | select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t4`.`id` AS `id`,`test`.`t4`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) left join `test`.`t4` on((`test`.`t4`.`id` = `test`.`t1`.`b`)) where ((`test`.`t2`.`x` = 1) and (`f1`(`test`.`t1`.`id`,'1980-01-01') = `test`.`t2`.`id`)) |
|
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
From this output I see that the IN subquery in converted to a semi-join with a extra conjunct in
WHERE (`f1`(`test`.`t1`.`id`,'1980-01-01') = `test`.`t2`.`id`)) and that semi-join is materialized.
I debugger I see that the added conjunct is attached to the result of materialization of the semi-join as (`f1`(`test`.`t1`.`id`,'1980-01-01') = `sj-materialize`.`id`) and to the last table t4 as
(`f1`(`test`.`t1`.`id`,'1980-01-01') = `test`.`t2`.`id`).
The latter condition cannot be correctly evaluated as table t2 is used only during materialization and after this `t2`.`id` is set to NULL.
|