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)
{ {
(*ref)->fix_after_pullout(new_parent, ref);
if (depended_from == new_parent) if (depended_from == new_parent)
{
(*ref)->fix_after_pullout(new_parent, ref);
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
...@@ -407,8 +409,10 @@ void JOIN_CACHE::set_constants() ...@@ -407,8 +409,10 @@ void JOIN_CACHE::set_constants()
However at this moment we don't know whether we have referenced fields for However at this moment we don't know whether we have referenced fields for
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;
......
...@@ -5635,7 +5635,11 @@ void calc_used_field_length(THD *thd, JOIN_TAB *join_tab) ...@@ -5635,7 +5635,11 @@ void calc_used_field_length(THD *thd, JOIN_TAB *join_tab)
uint blob_length=(uint) (join_tab->table->file->stats.mean_rec_length- uint blob_length=(uint) (join_tab->table->file->stats.mean_rec_length-
(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->is_inner_table_of_outer_join() && (!tab->type == JT_ALL || cache_level <= 4) &&
!tab->is_single_inner_of_outer_join())) ((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_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