MDEV-16820 Lost 'Impossible where' from query with inexpensive subquery

This patch fixes another problem introduced by the patch for mdev-4817.
The latter changed Item_cond::fix_fields() in such a way that it could
call the virtual method is_expensive(). With the first its call
the method saves the result in Item::is_expensive_cache. For all next
calls the method returns the result from this cache. So if the item
once was determined as expensive the method always returns true.
For subqueries it's not good, because non-optimized subqueries always
is considered as expensive.
It means that the cache should be invalidated after the call of
optimize_constant_subqueries().
This commit is contained in:
Igor Babaev 2018-07-24 20:00:28 -07:00
parent 9cea4ccf12
commit d567f1611e
8 changed files with 107 additions and 0 deletions

View File

@ -7171,4 +7171,20 @@ a
5 5
SET @@optimizer_switch= @optimiser_switch_save; SET @@optimizer_switch= @optimiser_switch_save;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# MDEV-16820: impossible where with inexpensive subquery
#
create table t1 (a int) engine=myisam;
insert into t1 values (3), (1), (7);
create table t2 (b int, index idx(b));
insert into t2 values (2), (5), (3), (2);
explain select * from t1 where (select max(b) from t2) = 10;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
drop table t1,t2;
End of 5.5 tests End of 5.5 tests

View File

@ -7168,6 +7168,22 @@ a
5 5
SET @@optimizer_switch= @optimiser_switch_save; SET @@optimizer_switch= @optimiser_switch_save;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# MDEV-16820: impossible where with inexpensive subquery
#
create table t1 (a int) engine=myisam;
insert into t1 values (3), (1), (7);
create table t2 (b int, index idx(b));
insert into t2 values (2), (5), (3), (2);
explain select * from t1 where (select max(b) from t2) = 10;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
drop table t1,t2;
End of 5.5 tests End of 5.5 tests
set optimizer_switch=default; set optimizer_switch=default;
select @@optimizer_switch like '%materialization=on%'; select @@optimizer_switch like '%materialization=on%';

View File

@ -7166,5 +7166,21 @@ a
5 5
SET @@optimizer_switch= @optimiser_switch_save; SET @@optimizer_switch= @optimiser_switch_save;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# MDEV-16820: impossible where with inexpensive subquery
#
create table t1 (a int) engine=myisam;
insert into t1 values (3), (1), (7);
create table t2 (b int, index idx(b));
insert into t2 values (2), (5), (3), (2);
explain select * from t1 where (select max(b) from t2) = 10;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
drop table t1,t2;
End of 5.5 tests End of 5.5 tests
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;

View File

@ -7177,6 +7177,22 @@ a
5 5
SET @@optimizer_switch= @optimiser_switch_save; SET @@optimizer_switch= @optimiser_switch_save;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# MDEV-16820: impossible where with inexpensive subquery
#
create table t1 (a int) engine=myisam;
insert into t1 values (3), (1), (7);
create table t2 (b int, index idx(b));
insert into t2 values (2), (5), (3), (2);
explain select * from t1 where (select max(b) from t2) = 10;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
drop table t1,t2;
End of 5.5 tests End of 5.5 tests
set optimizer_switch=default; set optimizer_switch=default;
select @@optimizer_switch like '%subquery_cache=on%'; select @@optimizer_switch like '%subquery_cache=on%';

View File

@ -7166,6 +7166,22 @@ a
5 5
SET @@optimizer_switch= @optimiser_switch_save; SET @@optimizer_switch= @optimiser_switch_save;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# MDEV-16820: impossible where with inexpensive subquery
#
create table t1 (a int) engine=myisam;
insert into t1 values (3), (1), (7);
create table t2 (b int, index idx(b));
insert into t2 values (2), (5), (3), (2);
explain select * from t1 where (select max(b) from t2) = 10;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
drop table t1,t2;
End of 5.5 tests End of 5.5 tests
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
set @join_cache_level_for_subselect_test=NULL; set @join_cache_level_for_subselect_test=NULL;

View File

@ -6060,4 +6060,19 @@ and t1.a in (select `test`.`t3`.`c` from `test`.`t3`);
SET @@optimizer_switch= @optimiser_switch_save; SET @@optimizer_switch= @optimiser_switch_save;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
--echo #
--echo # MDEV-16820: impossible where with inexpensive subquery
--echo #
create table t1 (a int) engine=myisam;
insert into t1 values (3), (1), (7);
create table t2 (b int, index idx(b));
insert into t2 values (2), (5), (3), (2);
explain select * from t1 where (select max(b) from t2) = 10;
explain select * from t1 where (select max(b) from t2) = 10 and t1.a > 3;
drop table t1,t2;
--echo End of 5.5 tests --echo End of 5.5 tests

View File

@ -1234,6 +1234,11 @@ public:
{ {
return FALSE; return FALSE;
} }
bool cleanup_is_expensive_cache_processor(uchar *arg)
{
is_expensive_cache= (int8)(-1);
return 0;
}
/* To call bool function for all arguments */ /* To call bool function for all arguments */
struct bool_func_call_args struct bool_func_call_args

View File

@ -1098,6 +1098,13 @@ JOIN::optimize()
if (optimize_constant_subqueries()) if (optimize_constant_subqueries())
DBUG_RETURN(1); DBUG_RETURN(1);
if (conds && conds->has_subquery())
(void) conds->walk(&Item::cleanup_is_expensive_cache_processor,
0, (uchar*)0);
if (having && having->has_subquery())
(void) having->walk(&Item::cleanup_is_expensive_cache_processor,
0, (uchar*)0);
if (setup_jtbm_semi_joins(this, join_list, &conds)) if (setup_jtbm_semi_joins(this, join_list, &conds))
DBUG_RETURN(1); DBUG_RETURN(1);