Commit 440a803c authored by Sergey Petrunya's avatar Sergey Petrunya

Merge

parents 2c120604 6e236b7b
......@@ -1656,7 +1656,6 @@ a
0
0
DROP TABLE t2,t3,t4,t5;
set optimizer_switch=@subselect_sj_mat_tmp;
#
# BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization
#
......@@ -1703,6 +1702,31 @@ f3
7
DROP TABLE t1, t2, t3, t4;
set optimizer_switch=@tmp_860535;
#
# BUG#860553: Crash in create_ref_for_key with semijoin + materialization
#
CREATE TABLE t1 (f1 int) ;
CREATE TABLE t2 (f5 varchar(52) NOT NULL) ;
CREATE TABLE t3 (f1 varchar(3), f4 varchar(52) , KEY (f4), PRIMARY KEY (f1));
CREATE TABLE t4 (f3 int, KEY (f3));
INSERT INTO t4 VALUES (17),(20);
CREATE TABLE t5 (f2 int);
INSERT INTO t5 VALUES (0),(0);
SELECT *
FROM t1
JOIN t2
ON ( t2.f5 ) IN (
SELECT t3.f4
FROM t3
WHERE ( 1 ) IN (
SELECT t4.f3
FROM t4 , t5
)
);
f1 f5
DROP TABLE t1, t2, t3, t4, t5;
# This must be at the end:
set optimizer_switch=@subselect_sj_mat_tmp;
set @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on';
......
......@@ -593,7 +593,7 @@ select * from t1 left join t2 on (t2.a= t1.a and t2.a in (select pk from t3));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where
2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY PRIMARY 4 func 1 Using index
2 SUBQUERY t3 index PRIMARY PRIMARY 4 NULL 10 Using index
drop table t0, t1, t2, t3;
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
......
......@@ -1696,7 +1696,6 @@ a
0
0
DROP TABLE t2,t3,t4,t5;
set optimizer_switch=@subselect_sj_mat_tmp;
#
# BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization
#
......@@ -1743,3 +1742,28 @@ f3
7
DROP TABLE t1, t2, t3, t4;
set optimizer_switch=@tmp_860535;
#
# BUG#860553: Crash in create_ref_for_key with semijoin + materialization
#
CREATE TABLE t1 (f1 int) ;
CREATE TABLE t2 (f5 varchar(52) NOT NULL) ;
CREATE TABLE t3 (f1 varchar(3), f4 varchar(52) , KEY (f4), PRIMARY KEY (f1));
CREATE TABLE t4 (f3 int, KEY (f3));
INSERT INTO t4 VALUES (17),(20);
CREATE TABLE t5 (f2 int);
INSERT INTO t5 VALUES (0),(0);
SELECT *
FROM t1
JOIN t2
ON ( t2.f5 ) IN (
SELECT t3.f4
FROM t3
WHERE ( 1 ) IN (
SELECT t4.f3
FROM t4 , t5
)
);
f1 f5
DROP TABLE t1, t2, t3, t4, t5;
# This must be at the end:
set optimizer_switch=@subselect_sj_mat_tmp;
......@@ -1349,8 +1349,6 @@ WHERE t2.a = ALL (
DROP TABLE t2,t3,t4,t5;
set optimizer_switch=@subselect_sj_mat_tmp;
--echo #
--echo # BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization
--echo #
......@@ -1399,3 +1397,35 @@ SELECT * FROM t4;
DROP TABLE t1, t2, t3, t4;
set optimizer_switch=@tmp_860535;
--echo #
--echo # BUG#860553: Crash in create_ref_for_key with semijoin + materialization
--echo #
CREATE TABLE t1 (f1 int) ;
CREATE TABLE t2 (f5 varchar(52) NOT NULL) ;
CREATE TABLE t3 (f1 varchar(3), f4 varchar(52) , KEY (f4), PRIMARY KEY (f1));
CREATE TABLE t4 (f3 int, KEY (f3));
INSERT INTO t4 VALUES (17),(20);
CREATE TABLE t5 (f2 int);
INSERT INTO t5 VALUES (0),(0);
SELECT *
FROM t1
JOIN t2
ON ( t2.f5 ) IN (
SELECT t3.f4
FROM t3
WHERE ( 1 ) IN (
SELECT t4.f3
FROM t4 , t5
)
);
DROP TABLE t1, t2, t3, t4, t5;
--echo # This must be at the end:
set optimizer_switch=@subselect_sj_mat_tmp;
......@@ -209,6 +209,74 @@ enum_nested_loop_state
end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
/*
Check if Materialization strategy is allowed for given subquery predicate.
@param thd Thread handle
@param in_subs The subquery predicate
@param child_select The select inside predicate (the function will
check it is the only one)
@return TRUE - Materialization is applicable
FALSE - Otherwise
*/
bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
st_select_lex *child_select)
{
st_select_lex_unit* parent_unit= child_select->master_unit();
/*
Check if the subquery predicate can be executed via materialization.
The required conditions are:
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
point in materializing.
2A The upper query is not a table-less SELECT ... FROM DUAL. We
can't do materialization for SELECT .. FROM DUAL because it
does not call setup_subquery_materialization(). We could make
SELECT ... FROM DUAL call that function but that doesn't seem
to be the case that is worth handling.
3. Either the subquery predicate is a top-level predicate, or at
least one partial match strategy is enabled. If no partial match
strategy is enabled, then materialization cannot be used for
non-top-level queries because it cannot handle NULLs correctly.
4. Subquery is non-correlated
TODO:
This condition is too restrictive (limitation). It can be extended to:
(Subquery is non-correlated ||
Subquery is correlated to any query outer to IN predicate ||
(Subquery is correlated to the immediate outer query &&
Subquery !contains {GROUP BY, ORDER BY [LIMIT],
aggregate functions}) && subquery predicate is not under "NOT IN"))
(*) The subquery must be part of a SELECT statement. The current
condition also excludes multi-table update statements.
A note about prepared statements: we want the if-branch to be taken on
PREPARE and each EXECUTE. The rewrites are only done once, but we need
select_lex->sj_subselects list to be populated for every EXECUTE.
*/
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!child_select->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2
thd->lex->sql_command == SQLCOM_SELECT && // *
child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3
optimizer_flag(thd,
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
optimizer_flag(thd,
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) && //3
!in_subs->is_correlated) //4
{
return TRUE;
}
return FALSE;
}
/*
Check if we need JOIN::prepare()-phase subquery rewrites and if yes, do them
......@@ -381,52 +449,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
*/
if (in_subs)
{
/*
Check if the subquery predicate can be executed via materialization.
The required conditions are:
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
point in materializing.
2A The upper query is not a table-less SELECT ... FROM DUAL. We
can't do materialization for SELECT .. FROM DUAL because it
does not call setup_subquery_materialization(). We could make
SELECT ... FROM DUAL call that function but that doesn't seem
to be the case that is worth handling.
3. Either the subquery predicate is a top-level predicate, or at
least one partial match strategy is enabled. If no partial match
strategy is enabled, then materialization cannot be used for
non-top-level queries because it cannot handle NULLs correctly.
4. Subquery is non-correlated
TODO:
This condition is too restrictive (limitation). It can be extended to:
(Subquery is non-correlated ||
Subquery is correlated to any query outer to IN predicate ||
(Subquery is correlated to the immediate outer query &&
Subquery !contains {GROUP BY, ORDER BY [LIMIT],
aggregate functions}) && subquery predicate is not under "NOT IN"))
(*) The subquery must be part of a SELECT statement. The current
condition also excludes multi-table update statements.
A note about prepared statements: we want the if-branch to be taken on
PREPARE and each EXECUTE. The rewrites are only done once, but we need
select_lex->sj_subselects list to be populated for every EXECUTE.
*/
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!select_lex->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2
thd->lex->sql_command == SQLCOM_SELECT && // *
select_lex->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3
optimizer_flag(thd,
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
optimizer_flag(thd,
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) && //3
!in_subs->is_correlated) //4
{
if (is_materialization_applicable(thd, in_subs, select_lex))
{
in_subs->in_strategy|= SUBS_MATERIALIZATION;
/*
......@@ -914,6 +938,12 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
check_and_do_in_subquery_rewrites.
*/
in_subq->in_strategy= SUBS_IN_TO_EXISTS;
if (is_materialization_applicable(thd, in_subq,
in_subq->unit->first_select()))
{
in_subq->in_strategy|= SUBS_MATERIALIZATION;
}
in_subq= li++;
}
......@@ -1766,6 +1796,9 @@ int pull_out_semijoin_tables(JOIN *join)
All obtained information is saved and will be used by the main join
optimization pass.
NOTES
Because of Join::reoptimize(), this function may be called multiple times.
RETURN
FALSE Ok
......
......@@ -21576,6 +21576,15 @@ void JOIN::save_query_plan(Join_plan_state *save_to)
memcpy((uchar*) save_to->best_positions, (uchar*) best_positions,
sizeof(POSITION) * (table_count + 1));
memset(best_positions, 0, sizeof(POSITION) * (table_count + 1));
/* Save SJM nests */
List_iterator<TABLE_LIST> it(select_lex->sj_nests);
TABLE_LIST *tlist;
SJ_MATERIALIZATION_INFO **p_info= save_to->sj_mat_info;
while ((tlist= it++))
{
*(p_info++)= tlist->sj_mat_info;
}
}
......@@ -21616,6 +21625,14 @@ void JOIN::restore_query_plan(Join_plan_state *restore_from)
}
memcpy((uchar*) best_positions, (uchar*) restore_from->best_positions,
sizeof(POSITION) * (table_count + 1));
/* Restore SJM nests */
List_iterator<TABLE_LIST> it(select_lex->sj_nests);
TABLE_LIST *tlist;
SJ_MATERIALIZATION_INFO **p_info= restore_from->sj_mat_info;
while ((tlist= it++))
{
tlist->sj_mat_info= *(p_info++);
}
}
......@@ -21705,6 +21722,9 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
return REOPT_ERROR;
optimize_keyuse(this, &keyuse);
if (optimize_semijoin_nests(this, join_tables))
return REOPT_ERROR;
/* Re-run the join optimizer to compute a new query plan. */
if (choose_plan(this, join_tables))
return REOPT_ERROR;
......
......@@ -666,6 +666,7 @@ class JOIN :public Sql_alloc
KEYUSE *join_tab_keyuse[MAX_TABLES];
/* Copies of JOIN_TAB::checked_keys for each JOIN_TAB. */
key_map join_tab_checked_keys[MAX_TABLES];
SJ_MATERIALIZATION_INFO *sj_mat_info[MAX_TABLES];
public:
Join_plan_state()
{
......
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