MDEV-21243: Join buffer: condition is checked in wrong place for range access
In this scenario: - There is a possible range access for table T - And there is a ref access on the same index which uses fewer key parts - The join optimizer picks the ref access (because it is cheaper) - make_join_select applies this heuristic to switch to range: /* Range uses longer key; Use this instead of ref on key */ Join buffer will be used without having called JOIN_TAB::make_scan_filter(). This means, conditions that should be checked when reading table T will be checked after T is joined with the contents of the join buffer, instead. Fixed this by adding a make_scan_filter() check. (updated patch after backport to 10.3) (Fix testcase on Windows)
This commit is contained in:
parent
cba9ed1279
commit
9c3eca8514
@ -6056,4 +6056,76 @@ select f2 from t2,t1 where f2 = 0;
|
|||||||
f2
|
f2
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
set join_buffer_size=@save_join_buffer_size;
|
set join_buffer_size=@save_join_buffer_size;
|
||||||
|
#
|
||||||
|
# MDEV-21243: Join buffer: condition is checked in wrong place for range access
|
||||||
|
#
|
||||||
|
create table t1(a int primary key);
|
||||||
|
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||||
|
create table t2 (a int);
|
||||||
|
insert into t2 select A.a + 10*B.a from t1 A, t1 B;
|
||||||
|
create table t3 (
|
||||||
|
kp1 int,
|
||||||
|
kp2 int,
|
||||||
|
col1 int,
|
||||||
|
col2 int,
|
||||||
|
key (kp1, kp2)
|
||||||
|
);
|
||||||
|
insert into t3
|
||||||
|
select
|
||||||
|
A.a,
|
||||||
|
B.a,
|
||||||
|
A.a + 100*B.a,
|
||||||
|
A.a + 100*B.a
|
||||||
|
from
|
||||||
|
t2 A, t2 B;
|
||||||
|
analyze table t3;
|
||||||
|
Table Op Msg_type Msg_text
|
||||||
|
test.t3 analyze status Table is already up to date
|
||||||
|
# The following must have "B.col1 + 1 < 33333" attached to table B
|
||||||
|
# and not to the block-nl-join node:
|
||||||
|
explain format=json
|
||||||
|
select *
|
||||||
|
from t1 a, t3 b
|
||||||
|
where
|
||||||
|
b.kp1=a.a and
|
||||||
|
b.kp1 <= 10 and
|
||||||
|
b.kp2 <= 10 and
|
||||||
|
b.col1 +1 < 33333;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "a",
|
||||||
|
"access_type": "index",
|
||||||
|
"possible_keys": ["PRIMARY"],
|
||||||
|
"key": "PRIMARY",
|
||||||
|
"key_length": "4",
|
||||||
|
"used_key_parts": ["a"],
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100,
|
||||||
|
"attached_condition": "a.a <= 10",
|
||||||
|
"using_index": true
|
||||||
|
},
|
||||||
|
"block-nl-join": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "b",
|
||||||
|
"access_type": "range",
|
||||||
|
"possible_keys": ["kp1"],
|
||||||
|
"key": "kp1",
|
||||||
|
"key_length": "10",
|
||||||
|
"used_key_parts": ["kp1", "kp2"],
|
||||||
|
"rows": 836,
|
||||||
|
"filtered": 11.962,
|
||||||
|
"index_condition": "b.kp2 <= 10",
|
||||||
|
"attached_condition": "b.kp2 <= 10 and b.col1 + 1 < 33333"
|
||||||
|
},
|
||||||
|
"buffer_type": "flat",
|
||||||
|
"buffer_size": "256Kb",
|
||||||
|
"join_type": "BNL",
|
||||||
|
"attached_condition": "b.kp1 = a.a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop table t1,t2,t3;
|
||||||
set @@optimizer_switch=@save_optimizer_switch;
|
set @@optimizer_switch=@save_optimizer_switch;
|
||||||
|
@ -4014,5 +4014,45 @@ select f2 from t2,t1 where f2 = 0;
|
|||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
set join_buffer_size=@save_join_buffer_size;
|
set join_buffer_size=@save_join_buffer_size;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-21243: Join buffer: condition is checked in wrong place for range access
|
||||||
|
--echo #
|
||||||
|
create table t1(a int primary key);
|
||||||
|
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||||
|
create table t2 (a int);
|
||||||
|
insert into t2 select A.a + 10*B.a from t1 A, t1 B;
|
||||||
|
|
||||||
|
create table t3 (
|
||||||
|
kp1 int,
|
||||||
|
kp2 int,
|
||||||
|
col1 int,
|
||||||
|
col2 int,
|
||||||
|
key (kp1, kp2)
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into t3
|
||||||
|
select
|
||||||
|
A.a,
|
||||||
|
B.a,
|
||||||
|
A.a + 100*B.a,
|
||||||
|
A.a + 100*B.a
|
||||||
|
from
|
||||||
|
t2 A, t2 B;
|
||||||
|
analyze table t3;
|
||||||
|
|
||||||
|
--echo # The following must have "B.col1 + 1 < 33333" attached to table B
|
||||||
|
--echo # and not to the block-nl-join node:
|
||||||
|
explain format=json
|
||||||
|
select *
|
||||||
|
from t1 a, t3 b
|
||||||
|
where
|
||||||
|
b.kp1=a.a and
|
||||||
|
b.kp1 <= 10 and
|
||||||
|
b.kp2 <= 10 and
|
||||||
|
b.col1 +1 < 33333;
|
||||||
|
|
||||||
|
drop table t1,t2,t3;
|
||||||
|
|
||||||
# The following command must be the last one in the file
|
# The following command must be the last one in the file
|
||||||
set @@optimizer_switch=@save_optimizer_switch;
|
set @@optimizer_switch=@save_optimizer_switch;
|
||||||
|
@ -10966,6 +10966,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
if (i != join->const_tables && tab->use_quick != 2 &&
|
if (i != join->const_tables && tab->use_quick != 2 &&
|
||||||
!tab->first_inner)
|
!tab->first_inner)
|
||||||
{ /* Read with cache */
|
{ /* Read with cache */
|
||||||
|
/*
|
||||||
|
TODO: the execution also gets here when we will not be using
|
||||||
|
join buffer. Review these cases and perhaps, remove this call.
|
||||||
|
(The final decision whether to use join buffer is made in
|
||||||
|
check_join_cache_usage, so we should only call make_scan_filter()
|
||||||
|
there, too).
|
||||||
|
*/
|
||||||
if (tab->make_scan_filter())
|
if (tab->make_scan_filter())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
@ -11928,6 +11935,9 @@ uint check_join_cache_usage(JOIN_TAB *tab,
|
|||||||
if ((tab->cache= new (root) JOIN_CACHE_BNL(join, tab, prev_cache)))
|
if ((tab->cache= new (root) JOIN_CACHE_BNL(join, tab, prev_cache)))
|
||||||
{
|
{
|
||||||
tab->icp_other_tables_ok= FALSE;
|
tab->icp_other_tables_ok= FALSE;
|
||||||
|
/* If make_join_select() hasn't called make_scan_filter(), do it now */
|
||||||
|
if (!tab->cache_select && tab->make_scan_filter())
|
||||||
|
goto no_join_cache;
|
||||||
return (2 - MY_TEST(!prev_cache));
|
return (2 - MY_TEST(!prev_cache));
|
||||||
}
|
}
|
||||||
goto no_join_cache;
|
goto no_join_cache;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user