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

Merge

parents 2c120604 6e236b7b
...@@ -1656,7 +1656,6 @@ a ...@@ -1656,7 +1656,6 @@ a
0 0
0 0
DROP TABLE t2,t3,t4,t5; 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 # BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization
# #
...@@ -1703,6 +1702,31 @@ f3 ...@@ -1703,6 +1702,31 @@ f3
7 7
DROP TABLE t1, t2, t3, t4; DROP TABLE t1, t2, t3, t4;
set optimizer_switch=@tmp_860535; 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 @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; 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)); ...@@ -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 id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t1 ALL NULL NULL NULL NULL 3
1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where 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; drop table t0, t1, t2, t3;
create table t1 (a int); create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
......
...@@ -1696,7 +1696,6 @@ a ...@@ -1696,7 +1696,6 @@ a
0 0
0 0
DROP TABLE t2,t3,t4,t5; 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 # BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization
# #
...@@ -1743,3 +1742,28 @@ f3 ...@@ -1743,3 +1742,28 @@ f3
7 7
DROP TABLE t1, t2, t3, t4; DROP TABLE t1, t2, t3, t4;
set optimizer_switch=@tmp_860535; 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 ( ...@@ -1349,8 +1349,6 @@ WHERE t2.a = ALL (
DROP TABLE t2,t3,t4,t5; DROP TABLE t2,t3,t4,t5;
set optimizer_switch=@subselect_sj_mat_tmp;
--echo # --echo #
--echo # BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization --echo # BUG#860300: Second crash with get_fanout_with_deps() with semijoin + materialization
--echo # --echo #
...@@ -1399,3 +1397,35 @@ SELECT * FROM t4; ...@@ -1399,3 +1397,35 @@ SELECT * FROM t4;
DROP TABLE t1, t2, t3, t4; DROP TABLE t1, t2, t3, t4;
set optimizer_switch=@tmp_860535; 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 ...@@ -209,6 +209,74 @@ enum_nested_loop_state
end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); 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 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) ...@@ -381,52 +449,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
*/ */
if (in_subs) if (in_subs)
{ {
/* if (is_materialization_applicable(thd, in_subs, select_lex))
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
{
in_subs->in_strategy|= SUBS_MATERIALIZATION; in_subs->in_strategy|= SUBS_MATERIALIZATION;
/* /*
...@@ -914,6 +938,12 @@ bool convert_join_subqueries_to_semijoins(JOIN *join) ...@@ -914,6 +938,12 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
check_and_do_in_subquery_rewrites. check_and_do_in_subquery_rewrites.
*/ */
in_subq->in_strategy= SUBS_IN_TO_EXISTS; 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++; in_subq= li++;
} }
...@@ -1766,6 +1796,9 @@ int pull_out_semijoin_tables(JOIN *join) ...@@ -1766,6 +1796,9 @@ int pull_out_semijoin_tables(JOIN *join)
All obtained information is saved and will be used by the main join All obtained information is saved and will be used by the main join
optimization pass. optimization pass.
NOTES
Because of Join::reoptimize(), this function may be called multiple times.
RETURN RETURN
FALSE Ok FALSE Ok
......
...@@ -21576,6 +21576,15 @@ void JOIN::save_query_plan(Join_plan_state *save_to) ...@@ -21576,6 +21576,15 @@ void JOIN::save_query_plan(Join_plan_state *save_to)
memcpy((uchar*) save_to->best_positions, (uchar*) best_positions, memcpy((uchar*) save_to->best_positions, (uchar*) best_positions,
sizeof(POSITION) * (table_count + 1)); sizeof(POSITION) * (table_count + 1));
memset(best_positions, 0, 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) ...@@ -21616,6 +21625,14 @@ void JOIN::restore_query_plan(Join_plan_state *restore_from)
} }
memcpy((uchar*) best_positions, (uchar*) restore_from->best_positions, memcpy((uchar*) best_positions, (uchar*) restore_from->best_positions,
sizeof(POSITION) * (table_count + 1)); 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, ...@@ -21705,6 +21722,9 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
return REOPT_ERROR; return REOPT_ERROR;
optimize_keyuse(this, &keyuse); 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. */ /* Re-run the join optimizer to compute a new query plan. */
if (choose_plan(this, join_tables)) if (choose_plan(this, join_tables))
return REOPT_ERROR; return REOPT_ERROR;
......
...@@ -666,6 +666,7 @@ class JOIN :public Sql_alloc ...@@ -666,6 +666,7 @@ class JOIN :public Sql_alloc
KEYUSE *join_tab_keyuse[MAX_TABLES]; KEYUSE *join_tab_keyuse[MAX_TABLES];
/* Copies of JOIN_TAB::checked_keys for each JOIN_TAB. */ /* Copies of JOIN_TAB::checked_keys for each JOIN_TAB. */
key_map join_tab_checked_keys[MAX_TABLES]; key_map join_tab_checked_keys[MAX_TABLES];
SJ_MATERIALIZATION_INFO *sj_mat_info[MAX_TABLES];
public: public:
Join_plan_state() 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