Commit 3b40f78e authored by Igor Babaev's avatar Igor Babaev

Fixed a flaw in the implementation of condition push-down

for materialized views and derived tables: there were no
push-down if the view was defined as union of selects
without aggregation. Added test cases with such unions.

Adjusted result files after the merge of the code for mdev-9197.
parent 102fc629
This diff is collapsed.
This diff is collapsed.
......@@ -918,7 +918,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 96 100.00 Using where; Using temporary
1 PRIMARY <derived2> ref key0 key0 5 test.t1.i1 9 100.00 Using where
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
2 DERIVED t1 ALL NULL NULL NULL NULL 96 100.00
2 DERIVED t1 ALL NULL NULL NULL NULL 96 100.00 Using where
Warnings:
Note 1003 select straight_join distinct `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`v1` join `test`.`t2` where ((`test`.`t2`.`i` = `v1`.`id`) and (`v1`.`i1` = `test`.`t1`.`i1`) and (`v1`.`id` <> 3))
set join_buffer_size=1024;
......
......@@ -485,6 +485,7 @@ EXPLAIN
"materialized": {
"query_block": {
"select_id": 2,
"having_condition": "(cnt > 0)",
"filesort": {
"sort_key": "t1.a",
"temporary_table": {
......
......@@ -292,7 +292,7 @@ set optimizer_switch='derived_merge=off,derived_with_keys=off';
explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 Using where
2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
2 DERIVED t1 index_merge i1,i2,i8 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
set optimizer_switch=@tmp_optimizer_switch;
create table t3 like t0;
insert into t3 select * from t0;
......
......@@ -1491,7 +1491,7 @@ EXPLAIN EXTENDED
SELECT * FROM t1 JOIN v2 ON i1 = i2 WHERE a < b;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select NULL AS `i1`,`v2`.`i2` AS `i2`,`v2`.`a` AS `a`,`v2`.`b` AS `b` from `test`.`v2` where ((`v2`.`i2` = NULL) and (`v2`.`a` < `v2`.`b`))
DROP VIEW v2;
......
......@@ -436,7 +436,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY <derived3> ALL NULL NULL NULL NULL 3 Using where
3 DERIVED t1 ALL NULL NULL NULL NULL 3
3 DERIVED t1 ALL NULL NULL NULL NULL 3 Using where
SELECT * FROM t3
WHERE t3.b IN (SELECT v1.b FROM v1, t2
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
......@@ -451,7 +451,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY <derived3> ref key1 key1 8 const,const 0 Using where
3 DERIVED t1 ALL NULL NULL NULL NULL 3
3 DERIVED t1 ALL NULL NULL NULL NULL 3 Using where
SELECT * FROM t3
WHERE t3.b IN (SELECT v1.b FROM v1, t2
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
......
......@@ -78,6 +78,20 @@ create view v2_union as
select a, b, avg(c) as c from t1
where t1.c>300 group by a,b having c < 707;
create view v3_union as
select a, b, (a+1) as c from t1
where t1.a<10
union
select a, b, c from t1
where t1.b>10 and t1.c>100;
create view v4_union as
select a, b, max(c)-100 as c from t1
where t1.a<10 group by a,b having c > 109
union
select a, b, (c+100) as c from t1
where t1.b>10;
create view v_double as
select a, avg(a/4) as avg_a, b, c from t1_double
where (b>12.2) group by b,c having (avg_a<22.333);
......@@ -683,6 +697,58 @@ eval $query;
eval explain $query;
eval explain format=json $query;
--echo # using derived table with union of selects without aggregation
--echo # extracted conjunctive predicate: pushing in WHERE of both selects
let $query=
select * from v3_union as v,t2 where (v.a=t2.a) and (v.c>6);
eval $no_pushdown $query;
eval $query;
eval explain $query;
eval explain format=json $query;
--echo # using derived table with union of selects without aggregation
--echo # extracted conjunctive OR subformula: pushing in WHERE using equalities
let $query=
select * from v3_union as v,t2 where (v.a=t2.a) and ((t2.a>1) or (v.b<20));
eval $no_pushdown $query;
eval $query;
eval explain $query;
eval explain format=json $query;
--echo # using derived table with union of selects without aggregation
--echo # extracted the whole condition: in WHERE of both selects
let $query=
select * from v3_union as v,t2 where
(v.a=t2.a) and ((v.b=19) or (v.b=21)) and ((v.c<3) or (v.c>600));
eval $no_pushdown $query;
eval $query;
eval explain $query;
eval explain format=json $query;
--echo # using derived table with union of
--echo # a select without aggregation and a select with aggregation
--echo # extracted conjunctive predicate: pushing in WHERE of both selects
let $query=
select * from v4_union as v,t2 where (v.a=t2.a) and (v.b<20);
eval $no_pushdown $query;
eval $query;
eval explain $query;
eval explain format=json $query;
--echo # using derived table with union of
--echo # a select without aggregation and a select with aggregation
--echo # extracted subformula: pushing in WHERE of one select
--echo # extracted subformula: pushing in HAVING of the other select
--echo # extracted sub-subformula: pushing in WHERE of the other select
--echo # using an equality in all pushdowns
let $query=
select * from v4_union as v,t2 where
(v.a=t2.a) and ((t2.a<3) or (v.b<40)) and (v.c>500);
eval $no_pushdown $query;
eval $query;
eval explain $query;
eval explain format=json $query;
--echo # using embedded derived table : pushing the same conditions
--echo # using several derived tables : pushing in all tables
--echo # conjunctive subformula : pushing into WHERE
......@@ -808,5 +874,7 @@ eval $query;
eval explain $query;
eval explain format=json $query;
drop view v1,v2,v3,v4,v_union,v2_union,v_double,v_char,v_decimal;
drop view v1,v2,v3,v4;
drop view v_union,v2_union,v3_union,v4_union;
drop view v_double,v_char,v_decimal;
drop table t1,t2,t1_double,t2_double,t1_char,t2_char,t1_decimal,t2_decimal;
\ No newline at end of file
......@@ -113,6 +113,7 @@ select * from t1 join v2 on f1=f2;
show status like 'Handler_read%';
explain extended select * from v1 join v4 on f1=f2;
explain format=json select * from v1 join v4 on f1=f2;
select * from v1 join v4 on f1=f2;
--echo merged derived in merged derived
......@@ -136,15 +137,24 @@ select * from (select * from
--echo materialized derived in materialized derived
explain extended select * from (select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2 group by f1) zz;
explain format=json select * from (select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2 group by f1) zz;
select * from (select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2 group by f1) zz;
--echo mat in merged derived join mat in merged derived
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='condition_pushdown_for_derived=off';
explain extended select * from
(select * from (select * from t1 where f1 < 7 group by f1) tt where f1 > 2) x
join
(select * from (select * from t1 where f1 < 7 group by f1) tt where f1 > 2) z
on x.f1 = z.f1;
explain format=json select * from
(select * from (select * from t1 where f1 < 7 group by f1) tt where f1 > 2) x
join
(select * from (select * from t1 where f1 < 7 group by f1) tt where f1 > 2) z
on x.f1 = z.f1;
flush status;
select * from
......@@ -154,6 +164,7 @@ join
on x.f1 = z.f1;
show status like 'Handler_read%';
flush status;
set optimizer_switch=@save_optimizer_switch;
--echo merged in merged derived join merged in merged derived
explain extended select * from
......@@ -181,6 +192,13 @@ join
(select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2 group by f1) z
on x.f1 = z.f1;
explain format=json select * from
(select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2 group by f1) x
join
(select * from
(select * from t1 where f1 < 7 group by f1) tt where f1 > 2 group by f1) z
on x.f1 = z.f1;
select * from
(select * from
......@@ -198,6 +216,8 @@ select * from (select * from v4 group by 1) tt;
--echo materialized view in merged derived
explain extended
select * from ( select * from v1 where f1 < 7) tt;
explain format=json
select * from ( select * from v1 where f1 < 7) tt;
select * from ( select * from v1 where f1 < 7) tt;
--echo merged view in a merged view in a merged derived
......
......@@ -6817,6 +6817,42 @@ Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
Item *Item_field::derived_field_transformer_for_where(THD *thd, uchar *arg)
{
Item *producing_item;
st_select_lex *sl= (st_select_lex *)arg;
List_iterator_fast<Item> li(sl->item_list);
table_map map= sl->master_unit()->derived->table->map;
if (used_tables() == map)
{
uint field_no= ((Item_field*) this)->field->field_index;
for (uint i= 0; i <= field_no; i++)
producing_item= li++;
return producing_item->build_clone(thd, thd->mem_root);
}
else if (((Item_field*)this)->item_equal)
{
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
Item_equal_fields_iterator it(*cond);
Item *item;
while ((item=it++))
{
if (item->used_tables() == map && item->type() == FIELD_ITEM)
{
Item_field *field_item= (Item_field *) item;
li.rewind();
uint field_no= ((Item_field*) this)->field->field_index;
for (uint i= 0; i <= field_no; i++)
producing_item= li++;
return producing_item->build_clone(thd, thd->mem_root);
}
}
}
return this;
}
Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
uchar *arg)
{
st_select_lex *sl= (st_select_lex *)arg;
List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
......
......@@ -1695,6 +1695,9 @@ class Item: public Value_source,
{ return this; }
virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg)
{ return this; }
virtual Item *derived_grouping_field_transformer_for_where(THD *thd,
uchar *arg)
{ return this; }
virtual bool expr_cache_is_needed(THD *) { return FALSE; }
virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs)
......@@ -2578,8 +2581,9 @@ class Item_field :public Item_ident
Item_field *field_for_view_update() { return this; }
int fix_outer_field(THD *thd, Field **field, Item **reference);
virtual Item *update_value_transformer(THD *thd, uchar *select_arg);
virtual Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
bool exclusive_dependence_on_table_processor(void *map);
bool exclusive_dependence_on_grouping_fields_processor(void *arg);
......
......@@ -480,8 +480,10 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->set_materialized_derived();
if (!derived->table || !derived->table->is_created())
res= mysql_derived_create(thd, lex, derived);
#if 0
if (!res)
res= mysql_derived_fill(thd, lex, derived);
#endif
goto exit_merge;
}
......@@ -1130,6 +1132,22 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!cond)
return false;
st_select_lex_unit *unit= derived->get_unit();
st_select_lex *sl= unit->first_select();
/* Check whether any select of 'unit' allows condition pushdown */
bool any_select_allows_cond_pushdown= false;
for (; sl; sl= sl->next_select())
{
if (sl->cond_pushdown_is_allowed())
{
any_select_allows_cond_pushdown= true;
break;
}
}
if (!any_select_allows_cond_pushdown)
return false;
/* Do not push conditions into recursive with tables */
if (derived->is_recursive_with_table())
return false;
......@@ -1150,11 +1168,11 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
return false;
}
/* Push extracted_cond into every select of the unit specifying 'derived' */
st_select_lex_unit *unit= derived->get_unit();
st_select_lex *save_curr_select= thd->lex->current_select;
st_select_lex *sl= unit->first_select();
for (; sl; sl= sl->next_select())
{
if (!sl->cond_pushdown_is_allowed())
continue;
thd->lex->current_select= sl;
/*
For each select of the unit except the last one
......@@ -1165,6 +1183,31 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!extracted_cond_copy)
continue;
if (!sl->join->group_list && !sl->with_sum_func)
{
/* extracted_cond_copy is pushed into where of sl */
extracted_cond_copy= extracted_cond_copy->transform(thd,
&Item::derived_field_transformer_for_where,
(uchar*) sl);
if (extracted_cond_copy)
{
/*
Create the conjunction of the existing where condition of sl
and the pushed condition, take it as the new where condition of sl
and fix this new condition
*/
extracted_cond_copy->walk(&Item::cleanup_processor, 0, 0);
thd->change_item_tree(&sl->join->conds,
and_conds(thd, sl->join->conds,
extracted_cond_copy));
if (sl->join->conds->fix_fields(thd, &sl->join->conds))
goto err;
}
continue;
}
/*
Figure out what can be extracted from the pushed condition
that could be pushed into the where clause of sl
......@@ -1182,7 +1225,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
*/
if (cond_over_grouping_fields)
cond_over_grouping_fields= cond_over_grouping_fields->transform(thd,
&Item::derived_field_transformer_for_where,
&Item::derived_grouping_field_transformer_for_where,
(uchar*) sl);
if (cond_over_grouping_fields)
......@@ -1239,3 +1282,4 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
thd->lex->current_select= save_curr_select;
return true;
}
......@@ -1150,6 +1150,9 @@ class st_select_lex: public st_select_lex_node
bool have_window_funcs() const { return (window_funcs.elements !=0); }
bool cond_pushdown_is_allowed() const
{ return !have_window_funcs() && !olap; }
private:
bool m_non_agg_field_used;
bool m_agg_func_used;
......
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