mirror of
https://github.com/MariaDB/server.git
synced 2025-07-23 08:45:18 +03:00
MWL#89: Address review feedback (by Sergey Petrunia)
mysql-test/r/subselect4.result: Moved test case for LP BUG#718593 into the correct test file subselect_mat_cost_bugs.test. mysql-test/t/subselect4.test: Moved test case for LP BUG#718593 into the correct test file subselect_mat_cost_bugs.test.
This commit is contained in:
@ -1655,52 +1655,6 @@ f1b f2b f3b
|
|||||||
set @@optimizer_switch=@save_optimizer_switch;
|
set @@optimizer_switch=@save_optimizer_switch;
|
||||||
drop table t0,t1,t2;
|
drop table t0,t1,t2;
|
||||||
#
|
#
|
||||||
# LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
|
|
||||||
# Item_field::find_item_equal -> Item_equal::contains
|
|
||||||
#
|
|
||||||
set @save_optimizer_switch=@@optimizer_switch;
|
|
||||||
SET @@optimizer_switch = 'semijoin=off';
|
|
||||||
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
|
|
||||||
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
|
|
||||||
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
|
|
||||||
insert into t2 values (1,2), (3,4);
|
|
||||||
EXPLAIN
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
|
||||||
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
|
||||||
);
|
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
|
||||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
|
|
||||||
2 DEPENDENT SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
|
|
||||||
2 DEPENDENT SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
|
||||||
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
|
||||||
);
|
|
||||||
f12 f13
|
|
||||||
EXPLAIN
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
|
||||||
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
|
||||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
|
|
||||||
2 DEPENDENT SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
|
|
||||||
2 DEPENDENT SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
|
||||||
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
|
||||||
f12 f13
|
|
||||||
set @@optimizer_switch=@save_optimizer_switch;
|
|
||||||
drop table t1, t2;
|
|
||||||
#
|
|
||||||
# LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89
|
# LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89
|
||||||
#
|
#
|
||||||
set @save_optimizer_switch=@@optimizer_switch;
|
set @save_optimizer_switch=@@optimizer_switch;
|
||||||
|
@ -229,6 +229,72 @@ FROM t1 STRAIGHT_JOIN t2 ON t2.f3 = t1.f3
|
|||||||
WHERE t2.f3 = 'c');
|
WHERE t2.f3 = 'c');
|
||||||
f2 f3
|
f2 f3
|
||||||
drop table t1,t2,t3;
|
drop table t1,t2,t3;
|
||||||
|
#
|
||||||
|
# LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
|
||||||
|
# Item_field::find_item_equal -> Item_equal::contains
|
||||||
#
|
#
|
||||||
# LP BUG#718593 Crash in substitute_for_best_equal_field ->
|
set @save_optimizer_switch=@@optimizer_switch;
|
||||||
# eliminate_item_equal -> Item_field::find_item_equal -> Item_equal::contains
|
SET @@optimizer_switch = 'semijoin=off';
|
||||||
|
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
|
||||||
|
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
|
||||||
|
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
|
||||||
|
insert into t2 values (1,2), (3,4);
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE ( f12 ) IN (
|
||||||
|
SELECT alias2.f3
|
||||||
|
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
||||||
|
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
||||||
|
);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE ( f12 ) IN (
|
||||||
|
SELECT alias2.f3
|
||||||
|
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
||||||
|
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
||||||
|
);
|
||||||
|
f12 f13
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE ( f12 ) IN (
|
||||||
|
SELECT alias2.f3
|
||||||
|
FROM t1 AS alias1, t1 AS alias2
|
||||||
|
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE ( f12 ) IN (
|
||||||
|
SELECT alias2.f3
|
||||||
|
FROM t1 AS alias1, t1 AS alias2
|
||||||
|
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
||||||
|
f12 f13
|
||||||
|
set @@optimizer_switch=@save_optimizer_switch;
|
||||||
|
drop table t1, t2;
|
||||||
|
#
|
||||||
|
# MWL#89: test introduced after Sergey Petrunia's review - test that
|
||||||
|
# keyparts wihtout index prefix are used with the IN-EXISTS strategy.
|
||||||
|
#
|
||||||
|
create table t1 (c1 int);
|
||||||
|
insert into t1 values (1), (2), (3);
|
||||||
|
create table t2 (kp1 int, kp2 int, c2 int, filler char(100));
|
||||||
|
insert into t2 values (0,0,0,'filler'),(0,1,1,'filler'),(0,2,2,'filler'),(0,3,3,'filler');
|
||||||
|
create index key1 on t2 (kp1, kp2);
|
||||||
|
create index key2 on t2 (kp1);
|
||||||
|
create index key3 on t2 (kp2);
|
||||||
|
set session optimizer_switch='default';
|
||||||
|
analyze table t2;
|
||||||
|
Table Op Msg_type Msg_text
|
||||||
|
test.t2 analyze status OK
|
||||||
|
explain
|
||||||
|
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
2 DEPENDENT SUBQUERY t2 index_subquery key1,key2,key3 key1 10 func,const 1 Using where
|
||||||
|
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
|
||||||
|
c1
|
||||||
|
drop table t1, t2;
|
||||||
|
@ -1328,48 +1328,6 @@ set @@optimizer_switch=@save_optimizer_switch;
|
|||||||
|
|
||||||
drop table t0,t1,t2;
|
drop table t0,t1,t2;
|
||||||
|
|
||||||
--echo #
|
|
||||||
--echo # LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
|
|
||||||
--echo # Item_field::find_item_equal -> Item_equal::contains
|
|
||||||
--echo #
|
|
||||||
|
|
||||||
set @save_optimizer_switch=@@optimizer_switch;
|
|
||||||
SET @@optimizer_switch = 'semijoin=off';
|
|
||||||
|
|
||||||
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
|
|
||||||
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
|
|
||||||
|
|
||||||
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
|
|
||||||
insert into t2 values (1,2), (3,4);
|
|
||||||
|
|
||||||
EXPLAIN
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
|
||||||
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
|
||||||
);
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
|
||||||
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
|
||||||
);
|
|
||||||
|
|
||||||
EXPLAIN
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
|
||||||
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE ( f12 ) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
|
||||||
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
|
||||||
|
|
||||||
set @@optimizer_switch=@save_optimizer_switch;
|
|
||||||
drop table t1, t2;
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89
|
--echo # LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89
|
||||||
|
@ -258,54 +258,71 @@ WHERE ( f2 ) IN (SELECT t1.f1
|
|||||||
drop table t1,t2,t3;
|
drop table t1,t2,t3;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
|
||||||
|
--echo # Item_field::find_item_equal -> Item_equal::contains
|
||||||
--echo #
|
--echo #
|
||||||
--echo # LP BUG#718593 Crash in substitute_for_best_equal_field ->
|
|
||||||
--echo # eliminate_item_equal -> Item_field::find_item_equal -> Item_equal::contains
|
|
||||||
|
|
||||||
--disable_parsing # not yet fixed
|
set @save_optimizer_switch=@@optimizer_switch;
|
||||||
|
SET @@optimizer_switch = 'semijoin=off';
|
||||||
|
|
||||||
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
|
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
|
||||||
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
|
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
|
||||||
|
|
||||||
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
|
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
|
||||||
|
|
||||||
set @save_optimizer_switch=@@optimizer_switch;
|
|
||||||
set @@optimizer_switch='materialization=off,in_to_exists=on,semijoin=off';
|
|
||||||
|
|
||||||
EXPLAIN
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE (f12) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
|
||||||
WHERE (alias2.f10 = alias1.f11) AND
|
|
||||||
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
|
||||||
|
|
||||||
SELECT * FROM t2
|
|
||||||
WHERE (f12) IN (
|
|
||||||
SELECT alias2.f3
|
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
|
||||||
WHERE (alias2.f10 = alias1.f11) AND
|
|
||||||
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
|
||||||
|
|
||||||
insert into t2 values (1,2), (3,4);
|
insert into t2 values (1,2), (3,4);
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
SELECT * FROM t2
|
SELECT * FROM t2
|
||||||
WHERE (f12) IN (
|
WHERE ( f12 ) IN (
|
||||||
SELECT alias2.f3
|
SELECT alias2.f3
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
||||||
WHERE (alias2.f10 = alias1.f11) AND
|
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
||||||
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
);
|
||||||
|
|
||||||
SELECT * FROM t2
|
SELECT * FROM t2
|
||||||
WHERE (f12) IN (
|
WHERE ( f12 ) IN (
|
||||||
SELECT alias2.f3
|
SELECT alias2.f3
|
||||||
FROM t1 AS alias1, t1 AS alias2
|
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
|
||||||
WHERE (alias2.f10 = alias1.f11) AND
|
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
|
||||||
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
);
|
||||||
|
|
||||||
set session optimizer_switch=@save_optimizer_switch;
|
EXPLAIN
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE ( f12 ) IN (
|
||||||
|
SELECT alias2.f3
|
||||||
|
FROM t1 AS alias1, t1 AS alias2
|
||||||
|
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
||||||
|
SELECT * FROM t2
|
||||||
|
WHERE ( f12 ) IN (
|
||||||
|
SELECT alias2.f3
|
||||||
|
FROM t1 AS alias1, t1 AS alias2
|
||||||
|
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
|
||||||
|
|
||||||
|
set @@optimizer_switch=@save_optimizer_switch;
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
|
||||||
--enable_parsing
|
|
||||||
|
--echo #
|
||||||
|
--echo # MWL#89: test introduced after Sergey Petrunia's review - test that
|
||||||
|
--echo # keyparts wihtout index prefix are used with the IN-EXISTS strategy.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (c1 int);
|
||||||
|
insert into t1 values (1), (2), (3);
|
||||||
|
|
||||||
|
create table t2 (kp1 int, kp2 int, c2 int, filler char(100));
|
||||||
|
insert into t2 values (0,0,0,'filler'),(0,1,1,'filler'),(0,2,2,'filler'),(0,3,3,'filler');
|
||||||
|
|
||||||
|
create index key1 on t2 (kp1, kp2);
|
||||||
|
create index key2 on t2 (kp1);
|
||||||
|
create index key3 on t2 (kp2);
|
||||||
|
|
||||||
|
set session optimizer_switch='default';
|
||||||
|
|
||||||
|
analyze table t2;
|
||||||
|
|
||||||
|
explain
|
||||||
|
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
|
||||||
|
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
|
||||||
|
|
||||||
|
drop table t1, t2;
|
||||||
|
@ -2096,13 +2096,14 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, uchar *argument
|
|||||||
|
|
||||||
bool Item_in_optimizer::is_expensive_processor(uchar *arg)
|
bool Item_in_optimizer::is_expensive_processor(uchar *arg)
|
||||||
{
|
{
|
||||||
return args[1]->is_expensive_processor(arg);
|
return args[0]->is_expensive_processor(arg) ||
|
||||||
|
args[1]->is_expensive_processor(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_in_optimizer::is_expensive()
|
bool Item_in_optimizer::is_expensive()
|
||||||
{
|
{
|
||||||
return args[1]->is_expensive();
|
return args[0]->is_expensive() || args[1]->is_expensive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -464,7 +464,7 @@ public:
|
|||||||
Item_in_subselect()
|
Item_in_subselect()
|
||||||
:Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
|
:Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
|
||||||
optimizer(0), abort_on_null(0),
|
optimizer(0), abort_on_null(0),
|
||||||
pushed_cond_guards(NULL), func(NULL), in_strategy(0),
|
pushed_cond_guards(NULL), func(NULL), in_strategy(SUBS_NOT_TRANSFORMED),
|
||||||
upper_item(0)
|
upper_item(0)
|
||||||
{}
|
{}
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
@ -205,18 +205,19 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
|||||||
!optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
|
!optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
|
||||||
my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0));
|
my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the subquery predicate is IN/=ANY, analyse and set all possible
|
||||||
|
subquery execution strategies based on optimizer switches and syntactic
|
||||||
|
properties.
|
||||||
|
*/
|
||||||
if (in_subs)
|
if (in_subs)
|
||||||
{
|
{
|
||||||
/* Subquery predicate is an IN/=ANY predicate. */
|
|
||||||
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS))
|
|
||||||
in_subs->in_strategy|= SUBS_IN_TO_EXISTS;
|
|
||||||
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
|
|
||||||
in_subs->in_strategy|= SUBS_MATERIALIZATION;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if the subquery predicate can be executed via materialization.
|
Check if the subquery predicate can be executed via materialization.
|
||||||
The required conditions are:
|
The required conditions are:
|
||||||
1. Subquery is a single SELECT (not a UNION)
|
0. The materialization optimizer switch was set.
|
||||||
|
1. Subquery is a single SELECT (not a UNION).
|
||||||
|
TODO: this is a limitation that can be fixed
|
||||||
2. Subquery is not a table-less query. In this case there is no
|
2. Subquery is not a table-less query. In this case there is no
|
||||||
point in materializing.
|
point in materializing.
|
||||||
2A The upper query is not a table-less SELECT ... FROM DUAL. We
|
2A The upper query is not a table-less SELECT ... FROM DUAL. We
|
||||||
@ -230,7 +231,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
|||||||
non-top-level queries because it cannot handle NULLs correctly.
|
non-top-level queries because it cannot handle NULLs correctly.
|
||||||
4. Subquery is non-correlated
|
4. Subquery is non-correlated
|
||||||
TODO:
|
TODO:
|
||||||
This is an overly restrictive condition. It can be extended to:
|
This condition is too restrictive (limitation). It can be extended to:
|
||||||
(Subquery is non-correlated ||
|
(Subquery is non-correlated ||
|
||||||
Subquery is correlated to any query outer to IN predicate ||
|
Subquery is correlated to any query outer to IN predicate ||
|
||||||
(Subquery is correlated to the immediate outer query &&
|
(Subquery is correlated to the immediate outer query &&
|
||||||
@ -240,30 +241,30 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
|
|||||||
(*) The subquery must be part of a SELECT statement. The current
|
(*) The subquery must be part of a SELECT statement. The current
|
||||||
condition also excludes multi-table update statements.
|
condition also excludes multi-table update statements.
|
||||||
*/
|
*/
|
||||||
if (!(in_subs->in_strategy & SUBS_MATERIALIZATION &&
|
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
|
||||||
!select_lex->is_part_of_union() && // 1
|
!select_lex->is_part_of_union() && // 1
|
||||||
parent_unit->first_select()->leaf_tables && // 2
|
parent_unit->first_select()->leaf_tables && // 2
|
||||||
thd->lex->sql_command == SQLCOM_SELECT && // *
|
thd->lex->sql_command == SQLCOM_SELECT && // *
|
||||||
select_lex->outer_select()->leaf_tables && // 2A
|
select_lex->outer_select()->leaf_tables && // 2A
|
||||||
subquery_types_allow_materialization(in_subs) &&
|
subquery_types_allow_materialization(in_subs) &&
|
||||||
// psergey-todo: duplicated_subselect_card_check: where it's done?
|
(in_subs->is_top_level_item() || //3
|
||||||
(in_subs->is_top_level_item() || //3
|
optimizer_flag(thd,
|
||||||
optimizer_flag(thd,
|
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
|
||||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
|
optimizer_flag(thd,
|
||||||
optimizer_flag(thd,
|
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) && //3
|
||||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) && //3
|
!in_subs->is_correlated) //4
|
||||||
!in_subs->is_correlated)) //4
|
|
||||||
{
|
{
|
||||||
/* Materialization is not possible based on syntactic properties. */
|
in_subs->in_strategy|= SUBS_MATERIALIZATION;
|
||||||
in_subs->in_strategy&= ~SUBS_MATERIALIZATION;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_subs->in_strategy)
|
/*
|
||||||
|
IN-TO-EXISTS is the only universal strategy. Choose it if the user
|
||||||
|
allowed it via an optimizer switch, or if materialization is not
|
||||||
|
possible.
|
||||||
|
*/
|
||||||
|
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) ||
|
||||||
|
!in_subs->in_strategy)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
If neither materialization is possible, nor the user chose
|
|
||||||
IN-TO-EXISTS, choose IN-TO-EXISTS as the only universal strategy.
|
|
||||||
*/
|
|
||||||
in_subs->in_strategy|= SUBS_IN_TO_EXISTS;
|
in_subs->in_strategy|= SUBS_IN_TO_EXISTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3703,10 +3704,9 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
|
|||||||
enum_reopt_result reopt_result= REOPT_NONE;
|
enum_reopt_result reopt_result= REOPT_NONE;
|
||||||
Item_in_subselect *in_subs;
|
Item_in_subselect *in_subs;
|
||||||
|
|
||||||
if (select_lex->master_unit()->item &&
|
if (is_in_subquery())
|
||||||
select_lex->master_unit()->item->is_in_predicate())
|
|
||||||
{
|
{
|
||||||
in_subs= (Item_in_subselect*) select_lex->master_unit()->item;
|
in_subs= (Item_in_subselect*) unit->item;
|
||||||
if (in_subs->create_in_to_exists_cond(this))
|
if (in_subs->create_in_to_exists_cond(this))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3943,11 +3943,10 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
|
|||||||
bool JOIN::choose_tableless_subquery_plan()
|
bool JOIN::choose_tableless_subquery_plan()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(!tables_list || !tables);
|
DBUG_ASSERT(!tables_list || !tables);
|
||||||
if (select_lex->master_unit()->item)
|
if (unit->item)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(select_lex->master_unit()->item->type() ==
|
DBUG_ASSERT(unit->item->type() == Item::SUBSELECT_ITEM);
|
||||||
Item::SUBSELECT_ITEM);
|
Item_subselect *subs_predicate= unit->item;
|
||||||
Item_subselect *subs_predicate= select_lex->master_unit()->item;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the optimizer determined that his query has an empty result,
|
If the optimizer determined that his query has an empty result,
|
||||||
@ -3990,4 +3989,3 @@ bool JOIN::choose_tableless_subquery_plan()
|
|||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3123,7 +3123,7 @@ bool st_select_lex::optimize_unflattened_subqueries()
|
|||||||
un->set_limit(un->global_parameters);
|
un->set_limit(un->global_parameters);
|
||||||
un->thd->lex->current_select= sl;
|
un->thd->lex->current_select= sl;
|
||||||
save_options= inner_join->select_options;
|
save_options= inner_join->select_options;
|
||||||
if (un->outer_select()->options & SELECT_DESCRIBE)
|
if (options & SELECT_DESCRIBE)
|
||||||
{
|
{
|
||||||
/* Optimize the subquery in the context of EXPLAIN. */
|
/* Optimize the subquery in the context of EXPLAIN. */
|
||||||
sl->set_explain_type();
|
sl->set_explain_type();
|
||||||
|
@ -260,7 +260,7 @@ public:
|
|||||||
list_node *node= first;
|
list_node *node= first;
|
||||||
list_node *list_first= list->first;
|
list_node *list_first= list->first;
|
||||||
elements=0;
|
elements=0;
|
||||||
while (node->info && node != list_first)
|
while (node != &end_of_list && node != list_first)
|
||||||
{
|
{
|
||||||
prev= &node->next;
|
prev= &node->next;
|
||||||
node= node->next;
|
node= node->next;
|
||||||
|
@ -57,7 +57,8 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
|
|||||||
uint tables, COND *conds,
|
uint tables, COND *conds,
|
||||||
table_map table_map, SELECT_LEX *select_lex,
|
table_map table_map, SELECT_LEX *select_lex,
|
||||||
st_sargable_param **sargables);
|
st_sargable_param **sargables);
|
||||||
static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse);
|
static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse,
|
||||||
|
bool skip_unprefixed_keyparts);
|
||||||
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
||||||
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
||||||
table_map used_tables);
|
table_map used_tables);
|
||||||
@ -914,7 +915,6 @@ JOIN::optimize()
|
|||||||
"Impossible HAVING" : "Impossible WHERE";
|
"Impossible HAVING" : "Impossible WHERE";
|
||||||
tables= 0;
|
tables= 0;
|
||||||
error= 0;
|
error= 0;
|
||||||
choose_tableless_subquery_plan();
|
|
||||||
goto setup_subq_exit;
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -966,7 +966,6 @@ JOIN::optimize()
|
|||||||
zero_result_cause= "No matching min/max row";
|
zero_result_cause= "No matching min/max row";
|
||||||
tables= 0;
|
tables= 0;
|
||||||
error=0;
|
error=0;
|
||||||
choose_tableless_subquery_plan();
|
|
||||||
goto setup_subq_exit;
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
if (res > 1)
|
if (res > 1)
|
||||||
@ -1007,7 +1006,6 @@ JOIN::optimize()
|
|||||||
{
|
{
|
||||||
DBUG_PRINT("info",("No tables"));
|
DBUG_PRINT("info",("No tables"));
|
||||||
error= 0;
|
error= 0;
|
||||||
choose_tableless_subquery_plan();
|
|
||||||
goto setup_subq_exit;
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
error= -1; // Error is sent to client
|
error= -1; // Error is sent to client
|
||||||
@ -1508,6 +1506,9 @@ JOIN::optimize()
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
setup_subq_exit:
|
setup_subq_exit:
|
||||||
|
/* Choose an execution strategy for this JOIN. */
|
||||||
|
if (!tables_list || !tables)
|
||||||
|
choose_tableless_subquery_plan();
|
||||||
/*
|
/*
|
||||||
Even with zero matching rows, subqueries in the HAVING clause may
|
Even with zero matching rows, subqueries in the HAVING clause may
|
||||||
need to be evaluated if there are aggregate functions in the query.
|
need to be evaluated if there are aggregate functions in the query.
|
||||||
@ -3036,7 +3037,16 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
|
|||||||
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
|
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
|
||||||
conds, ~outer_join, join->select_lex, &sargables))
|
conds, ~outer_join, join->select_lex, &sargables))
|
||||||
goto error;
|
goto error;
|
||||||
if (keyuse_array->elements && sort_and_filter_keyuse(keyuse_array))
|
/*
|
||||||
|
Keyparts without prefixes may be useful if this JOIN is a subquery, and
|
||||||
|
if the subquery may be executed via the IN-EXISTS strategy.
|
||||||
|
*/
|
||||||
|
bool skip_unprefixed_keyparts=
|
||||||
|
!(join->is_in_subquery() &&
|
||||||
|
((Item_in_subselect*)join->unit->item)->in_strategy & SUBS_IN_TO_EXISTS);
|
||||||
|
|
||||||
|
if (keyuse_array->elements &&
|
||||||
|
sort_and_filter_keyuse(keyuse_array, skip_unprefixed_keyparts))
|
||||||
goto error;
|
goto error;
|
||||||
DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
|
DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
|
||||||
}
|
}
|
||||||
@ -4505,7 +4515,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
Special treatment for ft-keys.
|
Special treatment for ft-keys.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse)
|
static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse,
|
||||||
|
bool skip_unprefixed_keyparts)
|
||||||
{
|
{
|
||||||
KEYUSE key_end, *prev, *save_pos, *use;
|
KEYUSE key_end, *prev, *save_pos, *use;
|
||||||
uint found_eq_constant, i;
|
uint found_eq_constant, i;
|
||||||
@ -4532,12 +4543,12 @@ static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse)
|
|||||||
{
|
{
|
||||||
if (use->key == prev->key && use->table == prev->table)
|
if (use->key == prev->key && use->table == prev->table)
|
||||||
{
|
{
|
||||||
if (prev->keypart+1 < use->keypart ||
|
if ((prev->keypart+1 < use->keypart && skip_unprefixed_keyparts) ||
|
||||||
(prev->keypart == use->keypart && found_eq_constant))
|
(prev->keypart == use->keypart && found_eq_constant))
|
||||||
continue; /* remove */
|
continue; /* remove */
|
||||||
}
|
}
|
||||||
else if (use->keypart != 0) // First found must be 0
|
else if (use->keypart != 0 && skip_unprefixed_keyparts)
|
||||||
continue;
|
continue; /* remove - first found must be 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
prev= use;
|
prev= use;
|
||||||
@ -16938,8 +16949,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
|||||||
select= tab->select;
|
select= tab->select;
|
||||||
|
|
||||||
/* Currently ORDER BY ... LIMIT is not supported in subqueries. */
|
/* Currently ORDER BY ... LIMIT is not supported in subqueries. */
|
||||||
DBUG_ASSERT(join->group_list ||
|
DBUG_ASSERT(join->group_list || !join->is_in_subquery());
|
||||||
!(join->unit->item && join->unit->item->is_in_predicate()));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When there is SQL_BIG_RESULT do not sort using index for GROUP BY,
|
When there is SQL_BIG_RESULT do not sort using index for GROUP BY,
|
||||||
@ -20659,7 +20669,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
|
|||||||
/* added_keyuse contents is copied, and it is no longer needed. */
|
/* added_keyuse contents is copied, and it is no longer needed. */
|
||||||
delete_dynamic(&added_keyuse);
|
delete_dynamic(&added_keyuse);
|
||||||
|
|
||||||
if (sort_and_filter_keyuse(&keyuse))
|
if (sort_and_filter_keyuse(&keyuse, true))
|
||||||
return REOPT_ERROR;
|
return REOPT_ERROR;
|
||||||
optimize_keyuse(this, &keyuse);
|
optimize_keyuse(this, &keyuse);
|
||||||
|
|
||||||
|
@ -1083,6 +1083,11 @@ public:
|
|||||||
double *read_time_arg, double *record_count_arg);
|
double *read_time_arg, double *record_count_arg);
|
||||||
/* defined in opt_subselect.cc */
|
/* defined in opt_subselect.cc */
|
||||||
bool transform_max_min_subquery();
|
bool transform_max_min_subquery();
|
||||||
|
/* True if this JOIN is a subquery under an IN predicate. */
|
||||||
|
bool is_in_subquery()
|
||||||
|
{
|
||||||
|
return (unit->item && unit->item->is_in_predicate());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user