Commit 292d4667 authored by unknown's avatar unknown

MWL#68 Subquery optimization: Efficient NOT IN execution with NULLs

Automerge with 5.3-subqueries
parents 6a138b7f c2924e15
...@@ -4142,3 +4142,46 @@ c1 c2 c1 c2 LENGTH(t2.c1) LENGTH(t2.c2) ...@@ -4142,3 +4142,46 @@ c1 c2 c1 c2 LENGTH(t2.c1) LENGTH(t2.c2)
2 2 tt uu 2 2 2 2 tt uu 2 2
set join_cache_level=default; set join_cache_level=default;
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# Bug #51092: linked join buffer is used for a 3-way cross join query
# that selects only records of the first table
#
create table t1 (a int, b int);
insert into t1 values (1,1),(2,2);
create table t2 (a int, b int);
insert into t2 values (1,1),(2,2);
create table t3 (a int, b int);
insert into t3 values (1,1),(2,2);
explain select t1.* from t1,t2,t3;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using join buffer
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using join buffer
select t1.* from t1,t2,t3;
a b
1 1
2 2
1 1
2 2
1 1
2 2
1 1
2 2
set join_cache_level=2;
explain select t1.* from t1,t2,t3;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using join buffer
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using join buffer
select t1.* from t1,t2,t3;
a b
1 1
2 2
1 1
2 2
1 1
2 2
1 1
2 2
set join_cache_level=default;
drop table t1,t2,t3;
...@@ -824,3 +824,50 @@ a ...@@ -824,3 +824,50 @@ a
3 3
2 2
drop table t1, t2, t3; drop table t1, t2, t3;
#
# Bug#49198 Wrong result for second call of procedure
# with view in subselect.
#
CREATE TABLE t1 (t1field integer, primary key (t1field));
CREATE TABLE t2 (t2field integer, primary key (t2field));
CREATE TABLE t3 (t3field integer, primary key (t3field));
CREATE VIEW v2 AS SELECT * FROM t2;
CREATE VIEW v3 AS SELECT * FROM t3;
INSERT INTO t1 VALUES(1),(2);
INSERT INTO t2 VALUES(1),(2);
INSERT INTO t3 VALUES(1),(2);
PREPARE stmt FROM
"
SELECT t1field
FROM t1
WHERE t1field IN (SELECT * FROM v2);
";
EXECUTE stmt;
t1field
1
2
EXECUTE stmt;
t1field
1
2
PREPARE stmt FROM
"
EXPLAIN
SELECT t1field
FROM t1
WHERE t1field IN (SELECT * FROM v2)
AND t1field IN (SELECT * FROM v3)
";
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 Using index
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
DROP TABLE t1, t2, t3;
DROP VIEW v2, v3;
# End of Bug#49198
...@@ -264,8 +264,8 @@ explain select * ...@@ -264,8 +264,8 @@ explain select *
from t0 where a in from t0 where a in
(select t2.a+t3.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a); (select t2.a+t3.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 10 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 Start temporary
1 PRIMARY t1 index NULL a 5 NULL 10 Using index; Start temporary; Using join buffer 1 PRIMARY t1 index NULL a 5 NULL 10 Using index; Using join buffer
1 PRIMARY t2 ref a a 5 test.t1.a 1 Using index 1 PRIMARY t2 ref a a 5 test.t1.a 1 Using index
1 PRIMARY t3 ref a a 5 test.t1.a 1 Using where; Using index; End temporary 1 PRIMARY t3 ref a a 5 test.t1.a 1 Using where; Using index; End temporary
drop table t0, t1,t2,t3; drop table t0, t1,t2,t3;
......
...@@ -268,8 +268,8 @@ explain select * ...@@ -268,8 +268,8 @@ explain select *
from t0 where a in from t0 where a in
(select t2.a+t3.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a); (select t2.a+t3.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 10 1 PRIMARY t0 ALL NULL NULL NULL NULL 10 Start temporary
1 PRIMARY t1 index NULL a 5 NULL 10 Using index; Start temporary; Using join buffer 1 PRIMARY t1 index NULL a 5 NULL 10 Using index; Using join buffer
1 PRIMARY t2 ref a a 5 test.t1.a 1 Using index 1 PRIMARY t2 ref a a 5 test.t1.a 1 Using index
1 PRIMARY t3 ref a a 5 test.t1.a 1 Using where; Using index; End temporary 1 PRIMARY t3 ref a a 5 test.t1.a 1 Using where; Using index; End temporary
drop table t0, t1,t2,t3; drop table t0, t1,t2,t3;
...@@ -421,20 +421,23 @@ explain extended select * from t0 ...@@ -421,20 +421,23 @@ explain extended select * from t0
where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and where t0.a in ( select t1.a from t1,t2 where t2.a=t0.a and
t1.b=t2.b); t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 1 PRIMARY t0 ALL NULL NULL NULL NULL 5 100.00 Start temporary
1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Start temporary; Using join buffer 1 PRIMARY t1 ref a a 5 test.t0.a 1 100.00 Using join buffer
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 Using where; End temporary; Using join buffer 1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 100.00 Using where; End temporary; Using join buffer
Warnings: Warnings:
Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1 Note 1276 Field or reference 'test.t0.a' of SELECT #2 was resolved in SELECT #1
Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where ((`test`.`t2`.`b` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t0`.`a`) and (`test`.`t2`.`a` = `test`.`t0`.`a`)) Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1`) join `test`.`t0` where ((`test`.`t2`.`b` = `test`.`t1`.`b`) and (`test`.`t1`.`a` = `test`.`t0`.`a`) and (`test`.`t2`.`a` = `test`.`t0`.`a`))
update t1 set a=3, b=11 where a=4; update t1 set a=3, b=11 where a=4;
update t2 set b=11 where a=3; update t2 set b=11 where a=3;
# Not anymore:
# The following query gives wrong result due to Bug#49129 # The following query gives wrong result due to Bug#49129
select * from t0 where t0.a in select * from t0 where t0.a in
(select t1.a from t1, t2 where t2.a=t0.a and t1.b=t2.b); (select t1.a from t1, t2 where t2.a=t0.a and t1.b=t2.b);
a a
0 0
1
2
3
drop table t0, t1, t2; drop table t0, t1, t2;
CREATE TABLE t1 ( CREATE TABLE t1 (
id int(11) NOT NULL, id int(11) NOT NULL,
...@@ -713,9 +716,9 @@ c2 in (select 1 from t3, t2) and ...@@ -713,9 +716,9 @@ c2 in (select 1 from t3, t2) and
c1 in (select convert(c6,char(1)) from t2); c1 in (select convert(c6,char(1)) from t2);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using join buffer
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; Using join buffer
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2) 1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2); Using join buffer
drop table t2, t3; drop table t2, t3;
set join_cache_level=default; set join_cache_level=default;
show variables like 'join_cache_level'; show variables like 'join_cache_level';
......
...@@ -374,8 +374,8 @@ WHERE PNUM IN ...@@ -374,8 +374,8 @@ WHERE PNUM IN
(SELECT PNUM FROM PROJ)); (SELECT PNUM FROM PROJ));
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY STAFF ALL NULL NULL NULL NULL 5 1 PRIMARY STAFF ALL NULL NULL NULL NULL 5
1 PRIMARY PROJ ALL NULL NULL NULL NULL 6 1 PRIMARY PROJ ALL NULL NULL NULL NULL 6 Using join buffer
1 PRIMARY WORKS ALL NULL NULL NULL NULL 12 Using where; FirstMatch(STAFF) 1 PRIMARY WORKS ALL NULL NULL NULL NULL 12 Using where; FirstMatch(STAFF); Using join buffer
SELECT EMPNUM, EMPNAME SELECT EMPNUM, EMPNAME
FROM STAFF FROM STAFF
WHERE EMPNUM IN WHERE EMPNUM IN
...@@ -828,6 +828,84 @@ a ...@@ -828,6 +828,84 @@ a
3 3
2 2
drop table t1, t2, t3; drop table t1, t2, t3;
#
# Bug#49198 Wrong result for second call of procedure
# with view in subselect.
#
CREATE TABLE t1 (t1field integer, primary key (t1field));
CREATE TABLE t2 (t2field integer, primary key (t2field));
CREATE TABLE t3 (t3field integer, primary key (t3field));
CREATE VIEW v2 AS SELECT * FROM t2;
CREATE VIEW v3 AS SELECT * FROM t3;
INSERT INTO t1 VALUES(1),(2);
INSERT INTO t2 VALUES(1),(2);
INSERT INTO t3 VALUES(1),(2);
PREPARE stmt FROM
"
SELECT t1field
FROM t1
WHERE t1field IN (SELECT * FROM v2);
";
EXECUTE stmt;
t1field
1
2
EXECUTE stmt;
t1field
1
2
PREPARE stmt FROM
"
EXPLAIN
SELECT t1field
FROM t1
WHERE t1field IN (SELECT * FROM v2)
AND t1field IN (SELECT * FROM v3)
";
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index PRIMARY PRIMARY 4 NULL 2 Using index
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.t1field 1 Using index
DROP TABLE t1, t2, t3;
DROP VIEW v2, v3;
# End of Bug#49198
#
# BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off
#
CREATE TABLE t0 (a INT);
INSERT INTO t0 VALUES (0),(1),(2),(3),(4);
CREATE TABLE t1 (a INT, b INT, KEY(a));
INSERT INTO t1 SELECT a, a from t0;
CREATE TABLE t2 (a INT, b INT, PRIMARY KEY(a));
INSERT INTO t2 SELECT * FROM t1;
UPDATE t1 SET a=3, b=11 WHERE a=4;
UPDATE t2 SET b=11 WHERE a=3;
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='firstmatch=off';
The following should use a join order of t0,t1,t2, with DuplicateElimination:
explain
SELECT * FROM t0 WHERE t0.a IN
(SELECT t1.a FROM t1, t2 WHERE t2.a=t0.a AND t1.b=t2.b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 ALL NULL NULL NULL NULL 5 Start temporary
1 PRIMARY t1 ref a a 5 test.t0.a 1 Using join buffer
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 Using where; End temporary; Using join buffer
SELECT * FROM t0 WHERE t0.a IN
(SELECT t1.a FROM t1, t2 WHERE t2.a=t0.a AND t1.b=t2.b);
a
0
1
2
3
set optimizer_switch=@save_optimizer_switch;
drop table t0, t1, t2;
# End
set join_cache_level=default; set join_cache_level=default;
show variables like 'join_cache_level'; show variables like 'join_cache_level';
Variable_name Value Variable_name Value
......
...@@ -2257,7 +2257,7 @@ EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE ...@@ -2257,7 +2257,7 @@ EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer index NULL a 10 NULL 15 Using where; Using index 1 PRIMARY t1_outer index NULL a 10 NULL 15 Using where; Using index
2 DEPENDENT SUBQUERY t1 index NULL a 10 NULL 1 Using index 2 SUBQUERY t1 index NULL a 10 NULL 15 Using index
EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING
a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
......
This diff is collapsed.
...@@ -1823,3 +1823,27 @@ SELECT t1.*, t2.*, LENGTH(t2.c1), LENGTH(t2.c2) FROM t1,t2 ...@@ -1823,3 +1823,27 @@ SELECT t1.*, t2.*, LENGTH(t2.c1), LENGTH(t2.c2) FROM t1,t2
set join_cache_level=default; set join_cache_level=default;
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # Bug #51092: linked join buffer is used for a 3-way cross join query
--echo # that selects only records of the first table
--echo #
create table t1 (a int, b int);
insert into t1 values (1,1),(2,2);
create table t2 (a int, b int);
insert into t2 values (1,1),(2,2);
create table t3 (a int, b int);
insert into t3 values (1,1),(2,2);
explain select t1.* from t1,t2,t3;
select t1.* from t1,t2,t3;
set join_cache_level=2;
explain select t1.* from t1,t2,t3;
select t1.* from t1,t2,t3;
set join_cache_level=default;
drop table t1,t2,t3;
...@@ -728,3 +728,45 @@ where a in (select c from t2 where d >= some(select e from t3 where b=e)); ...@@ -728,3 +728,45 @@ where a in (select c from t2 where d >= some(select e from t3 where b=e));
drop table t1, t2, t3; drop table t1, t2, t3;
--echo #
--echo # Bug#49198 Wrong result for second call of procedure
--echo # with view in subselect.
--echo #
CREATE TABLE t1 (t1field integer, primary key (t1field));
CREATE TABLE t2 (t2field integer, primary key (t2field));
CREATE TABLE t3 (t3field integer, primary key (t3field));
CREATE VIEW v2 AS SELECT * FROM t2;
CREATE VIEW v3 AS SELECT * FROM t3;
INSERT INTO t1 VALUES(1),(2);
INSERT INTO t2 VALUES(1),(2);
INSERT INTO t3 VALUES(1),(2);
PREPARE stmt FROM
"
SELECT t1field
FROM t1
WHERE t1field IN (SELECT * FROM v2);
";
EXECUTE stmt;
EXECUTE stmt;
PREPARE stmt FROM
"
EXPLAIN
SELECT t1field
FROM t1
WHERE t1field IN (SELECT * FROM v2)
AND t1field IN (SELECT * FROM v3)
";
EXECUTE stmt;
EXECUTE stmt;
DROP TABLE t1, t2, t3;
DROP VIEW v2, v3;
--echo # End of Bug#49198
...@@ -583,7 +583,7 @@ update t2 set b=11 where a=3; ...@@ -583,7 +583,7 @@ update t2 set b=11 where a=3;
if (`select @@join_cache_level=6`) if (`select @@join_cache_level=6`)
{ {
--echo --echo # Not anymore:
--echo # The following query gives wrong result due to Bug#49129 --echo # The following query gives wrong result due to Bug#49129
} }
select * from t0 where t0.a in select * from t0 where t0.a in
......
...@@ -7,5 +7,33 @@ show variables like 'join_cache_level'; ...@@ -7,5 +7,33 @@ show variables like 'join_cache_level';
--source t/subselect_sj.test --source t/subselect_sj.test
--echo #
--echo # BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off
--echo #
CREATE TABLE t0 (a INT);
INSERT INTO t0 VALUES (0),(1),(2),(3),(4);
CREATE TABLE t1 (a INT, b INT, KEY(a));
INSERT INTO t1 SELECT a, a from t0;
CREATE TABLE t2 (a INT, b INT, PRIMARY KEY(a));
INSERT INTO t2 SELECT * FROM t1;
UPDATE t1 SET a=3, b=11 WHERE a=4;
UPDATE t2 SET b=11 WHERE a=3;
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='firstmatch=off';
--echo The following should use a join order of t0,t1,t2, with DuplicateElimination:
explain
SELECT * FROM t0 WHERE t0.a IN
(SELECT t1.a FROM t1, t2 WHERE t2.a=t0.a AND t1.b=t2.b);
SELECT * FROM t0 WHERE t0.a IN
(SELECT t1.a FROM t1, t2 WHERE t2.a=t0.a AND t1.b=t2.b);
set optimizer_switch=@save_optimizer_switch;
drop table t0, t1, t2;
--echo # End
set join_cache_level=default; set join_cache_level=default;
show variables like 'join_cache_level'; show variables like 'join_cache_level';
...@@ -6491,11 +6491,9 @@ void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref) ...@@ -6491,11 +6491,9 @@ void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr) void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
{ {
if (depended_from == new_parent)
{
(*ref)->fix_after_pullout(new_parent, ref); (*ref)->fix_after_pullout(new_parent, ref);
if (depended_from == new_parent)
depended_from= NULL; depended_from= NULL;
}
} }
......
...@@ -531,7 +531,6 @@ static bool replace_where_subcondition(JOIN *join, Item **expr, ...@@ -531,7 +531,6 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
*expr= new_cond; *expr= new_cond;
if (do_fix_fields) if (do_fix_fields)
new_cond->fix_fields(join->thd, expr); new_cond->fix_fields(join->thd, expr);
join->select_lex->where= *expr;
return FALSE; return FALSE;
} }
...@@ -3031,10 +3030,24 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, ...@@ -3031,10 +3030,24 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
forwards, but do not destroy other duplicate elimination methods. forwards, but do not destroy other duplicate elimination methods.
*/ */
uint first_table= i; uint first_table= i;
uint join_cache_level= join->thd->variables.join_cache_level;
for (uint j= i; j < i + pos->n_sj_tables; j++) for (uint j= i; j < i + pos->n_sj_tables; j++)
{ {
if (join->best_positions[j].use_join_buffer && j <= no_jbuf_after) /*
When we'll properly take join buffering into account during
join optimization, the below check should be changed to
"if (join->best_positions[j].use_join_buffer &&
j <= no_jbuf_after)".
For now, use a rough criteria:
*/
JOIN_TAB *js_tab=join->join_tab + j;
if (j != join->const_tables && js_tab->use_quick != 2 &&
j <= no_jbuf_after &&
((js_tab->type == JT_ALL && join_cache_level != 0) ||
(join_cache_level > 4 && (tab->type == JT_REF ||
tab->type == JT_EQ_REF))))
{ {
/* Looks like we'll be using join buffer */
first_table= join->const_tables; first_table= join->const_tables;
break; break;
} }
...@@ -3112,7 +3125,12 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, ...@@ -3112,7 +3125,12 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
JOIN_TAB *j, *jump_to= tab-1; JOIN_TAB *j, *jump_to= tab-1;
for (j= tab; j != tab + pos->n_sj_tables; j++) for (j= tab; j != tab + pos->n_sj_tables; j++)
{ {
if (!tab->emb_sj_nest) /*
NOTE: this loop probably doesn't do the right thing for the case
where FirstMatch's duplicate-generating range is interleaved with
"unrelated" tables (as specified in WL#3750, section 2.2).
*/
if (!j->emb_sj_nest)
jump_to= tab; jump_to= tab;
else else
{ {
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "sql_select.h" #include "sql_select.h"
#include "opt_subselect.h" #include "opt_subselect.h"
#define NO_MORE_RECORDS_IN_BUFFER (uint)(-1)
/***************************************************************************** /*****************************************************************************
* Join cache module * Join cache module
...@@ -408,7 +410,9 @@ void JOIN_CACHE::set_constants() ...@@ -408,7 +410,9 @@ void JOIN_CACHE::set_constants()
the cache or not. Later when a referenced field is registered for the cache the cache or not. Later when a referenced field is registered for the cache
we adjust the value of the flag 'with_length'. we adjust the value of the flag 'with_length'.
*/ */
with_length= is_key_access() || with_match_flag; with_length= is_key_access() ||
join_tab->is_inner_table_of_semi_join_with_first_match() ||
join_tab->is_inner_table_of_outer_join();
/* /*
At this moment we don't know yet the value of 'referenced_fields', At this moment we don't know yet the value of 'referenced_fields',
but in any case it can't be greater than the value of 'fields'. but in any case it can't be greater than the value of 'fields'.
...@@ -604,7 +608,12 @@ int JOIN_CACHE_BKA::init() ...@@ -604,7 +608,12 @@ int JOIN_CACHE_BKA::init()
copy_end= cache->field_descr+cache->fields; copy_end= cache->field_descr+cache->fields;
for (copy= cache->field_descr+cache->flag_fields; copy < copy_end; copy++) for (copy= cache->field_descr+cache->flag_fields; copy < copy_end; copy++)
{ {
if (copy->field->table == tab->table && /*
(1) - when we store rowids for DuplicateWeedout, they have
copy->field==NULL
*/
if (copy->field && // (1)
copy->field->table == tab->table &&
bitmap_is_set(key_read_set, copy->field->field_index)) bitmap_is_set(key_read_set, copy->field->field_index))
{ {
*copy_ptr++= copy; *copy_ptr++= copy;
...@@ -1235,7 +1244,7 @@ bool JOIN_CACHE::get_record() ...@@ -1235,7 +1244,7 @@ bool JOIN_CACHE::get_record()
prev_rec_ptr= prev_cache->get_rec_ref(pos); prev_rec_ptr= prev_cache->get_rec_ref(pos);
} }
curr_rec_pos= pos; curr_rec_pos= pos;
if (!(res= read_all_record_fields() == 0)) if (!(res= read_all_record_fields() == NO_MORE_RECORDS_IN_BUFFER))
{ {
pos+= referenced_fields*size_of_fld_ofs; pos+= referenced_fields*size_of_fld_ofs;
if (prev_cache) if (prev_cache)
...@@ -1304,7 +1313,7 @@ bool JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr) ...@@ -1304,7 +1313,7 @@ bool JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr)
uchar *prev_rec_ptr= prev_cache->get_rec_ref(rec_ptr); uchar *prev_rec_ptr= prev_cache->get_rec_ref(rec_ptr);
return prev_cache->get_match_flag_by_pos(prev_rec_ptr); return prev_cache->get_match_flag_by_pos(prev_rec_ptr);
} }
DBUG_ASSERT(1); DBUG_ASSERT(0);
return FALSE; return FALSE;
} }
...@@ -1324,7 +1333,8 @@ bool JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr) ...@@ -1324,7 +1333,8 @@ bool JOIN_CACHE::get_match_flag_by_pos(uchar *rec_ptr)
read data. read data.
RETURN RETURN
length of the data read from the join buffer (-1) - if there is no more records in the join buffer
length of the data read from the join buffer - otherwise
*/ */
uint JOIN_CACHE::read_all_record_fields() uint JOIN_CACHE::read_all_record_fields()
...@@ -1332,7 +1342,7 @@ uint JOIN_CACHE::read_all_record_fields() ...@@ -1332,7 +1342,7 @@ uint JOIN_CACHE::read_all_record_fields()
uchar *init_pos= pos; uchar *init_pos= pos;
if (pos > last_rec_pos || !records) if (pos > last_rec_pos || !records)
return 0; return NO_MORE_RECORDS_IN_BUFFER;
/* First match flag, read null bitmaps and null_row flag for each table */ /* First match flag, read null bitmaps and null_row flag for each table */
read_flag_fields(); read_flag_fields();
...@@ -1538,12 +1548,12 @@ bool JOIN_CACHE::read_referenced_field(CACHE_FIELD *copy, ...@@ -1538,12 +1548,12 @@ bool JOIN_CACHE::read_referenced_field(CACHE_FIELD *copy,
bool JOIN_CACHE::skip_record_if_match() bool JOIN_CACHE::skip_record_if_match()
{ {
DBUG_ASSERT(with_match_flag && with_length); DBUG_ASSERT(with_length);
uint offset= size_of_rec_len; uint offset= size_of_rec_len;
if (prev_cache) if (prev_cache)
offset+= prev_cache->get_size_of_rec_offset(); offset+= prev_cache->get_size_of_rec_offset();
/* Check whether the match flag is on */ /* Check whether the match flag is on */
if (test(*(pos+offset))) if (get_match_flag_by_pos(pos+offset))
{ {
pos+= size_of_rec_len + get_rec_length(pos); pos+= size_of_rec_len + get_rec_length(pos);
return TRUE; return TRUE;
......
...@@ -5636,6 +5636,10 @@ void calc_used_field_length(THD *thd, JOIN_TAB *join_tab) ...@@ -5636,6 +5636,10 @@ void calc_used_field_length(THD *thd, JOIN_TAB *join_tab)
(join_tab->table->s->reclength-rec_length)); (join_tab->table->s->reclength-rec_length));
rec_length+=(uint) max(4,blob_length); rec_length+=(uint) max(4,blob_length);
} }
/*
psergey-todo: why we don't count here rowid that we might need to store
when using DuplicateElimination?
*/
join_tab->used_fields=fields; join_tab->used_fields=fields;
join_tab->used_fieldlength=rec_length; join_tab->used_fieldlength=rec_length;
join_tab->used_blobs=blobs; join_tab->used_blobs=blobs;
...@@ -6355,10 +6359,17 @@ make_outerjoin_info(JOIN *join) ...@@ -6355,10 +6359,17 @@ make_outerjoin_info(JOIN *join)
} }
if (!tab->first_inner) if (!tab->first_inner)
tab->first_inner= nested_join->first_nested; tab->first_inner= nested_join->first_nested;
if (tab->table->reginfo.not_exists_optimize)
tab->first_inner->table->reginfo.not_exists_optimize= 1;
if (++nested_join->counter < nested_join->n_tables) if (++nested_join->counter < nested_join->n_tables)
break; break;
/* Table tab is the last inner table for nested join. */ /* Table tab is the last inner table for nested join. */
nested_join->first_nested->last_inner= tab; nested_join->first_nested->last_inner= tab;
if (tab->first_inner->table->reginfo.not_exists_optimize)
{
for (JOIN_TAB *join_tab= tab->first_inner; join_tab <= tab; join_tab++)
join_tab->table->reginfo.not_exists_optimize= 1;
}
} }
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -7111,19 +7122,15 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7111,19 +7122,15 @@ uint check_join_cache_usage(JOIN_TAB *tab,
*/ */
if (tab->use_quick == 2) if (tab->use_quick == 2)
goto no_join_cache; goto no_join_cache;
/*
Use join cache with FirstMatch semi-join strategy only when semi-join
contains only one table.
*/
if (tab->is_inner_table_of_semi_join_with_first_match() &&
!tab->is_single_inner_of_semi_join_with_first_match())
goto no_join_cache;
/* /*
Non-linked join buffers can't guarantee one match Non-linked join buffers can't guarantee one match
*/ */
if (force_unlinked_cache && if (force_unlinked_cache &&
(!tab->type == JT_ALL || cache_level <= 4) &&
((tab->is_inner_table_of_semi_join_with_first_match() &&
!tab->is_single_inner_of_semi_join_with_first_match()) ||
(tab->is_inner_table_of_outer_join() && (tab->is_inner_table_of_outer_join() &&
!tab->is_single_inner_of_outer_join())) !tab->is_single_inner_of_outer_join())))
goto no_join_cache; goto no_join_cache;
/* /*
......
...@@ -321,8 +321,8 @@ typedef struct st_join_table { ...@@ -321,8 +321,8 @@ typedef struct st_join_table {
} }
bool check_only_first_match() bool check_only_first_match()
{ {
return last_sj_inner_tab == this || return is_inner_table_of_semi_join_with_first_match() ||
(first_inner && first_inner->last_inner == this && (is_inner_table_of_outer_join() &&
table->reginfo.not_exists_optimize); table->reginfo.not_exists_optimize);
} }
bool is_last_inner_table() bool is_last_inner_table()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment