summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/derived_cond_pushdown.result236
-rw-r--r--mysql-test/t/derived_cond_pushdown.test36
-rw-r--r--sql/sql_derived.cc10
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_window.cc78
5 files changed, 356 insertions, 5 deletions
diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result
index a196709dad1..9c55c64ae32 100644
--- a/mysql-test/r/derived_cond_pushdown.result
+++ b/mysql-test/r/derived_cond_pushdown.result
@@ -9243,6 +9243,242 @@ EXPLAIN
}
}
}
+set statement optimizer_switch='condition_pushdown_for_derived=off' for select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a,c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+a c sum_b avg_b
+7 cc 28 14.0000
+7 cc 28 14.0000
+3 aa 92 46.0000
+7 bb 126 42.0000
+4 aa 15 15.0000
+7 bb 126 42.0000
+7 bb 126 42.0000
+3 bb 40 40.0000
+3 aa 92 46.0000
+select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a,c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+a c sum_b avg_b
+7 cc 28 14.0000
+7 cc 28 14.0000
+3 aa 92 46.0000
+7 bb 126 42.0000
+4 aa 15 15.0000
+7 bb 126 42.0000
+7 bb 126 42.0000
+3 bb 40 40.0000
+3 aa 92 46.0000
+explain select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a,c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 16 Using where
+2 DERIVED t2 ALL idx NULL NULL NULL 20 Using where; Using temporary
+explain format=json select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a,c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 16,
+ "filtered": 100,
+ "attached_condition": "t.a > 2 and t.c in ('aa','bb','cc')",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "window_functions_computation": {
+ "sorts": {
+ "filesort": {
+ "sort_key": "t2.a, t2.c"
+ }
+ },
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "possible_keys": ["idx"],
+ "rows": 20,
+ "filtered": 80,
+ "attached_condition": "t2.a > 2 and t2.c in ('aa','bb','cc')"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_for_derived=off' for select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+a c sum_b avg_b
+7 cc 28 30.8000
+7 cc 28 30.8000
+3 aa 92 44.0000
+7 bb 126 30.8000
+4 aa 15 46.3333
+7 bb 126 30.8000
+7 bb 126 30.8000
+3 bb 40 44.0000
+3 aa 92 44.0000
+select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+a c sum_b avg_b
+7 cc 28 30.8000
+7 cc 28 30.8000
+3 aa 92 44.0000
+7 bb 126 30.8000
+4 aa 15 46.3333
+7 bb 126 30.8000
+7 bb 126 30.8000
+3 bb 40 44.0000
+3 aa 92 44.0000
+explain select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 16 Using where
+2 DERIVED t2 ALL idx NULL NULL NULL 20 Using where; Using temporary
+explain format=json select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by a) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 16,
+ "filtered": 100,
+ "attached_condition": "t.a > 2 and t.c in ('aa','bb','cc')",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "window_functions_computation": {
+ "sorts": {
+ "filesort": {
+ "sort_key": "t2.a, t2.c"
+ }
+ },
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "possible_keys": ["idx"],
+ "rows": 20,
+ "filtered": 80,
+ "attached_condition": "t2.a > 2"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+set statement optimizer_switch='condition_pushdown_for_derived=off' for select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+a c sum_b avg_b
+7 cc 28 14.0000
+7 cc 28 14.0000
+3 aa 92 35.4000
+7 bb 126 36.5000
+4 aa 15 35.4000
+7 bb 126 36.5000
+7 bb 126 36.5000
+3 bb 40 36.5000
+3 aa 92 35.4000
+select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+a c sum_b avg_b
+7 cc 28 14.0000
+7 cc 28 14.0000
+3 aa 92 35.4000
+7 bb 126 36.5000
+4 aa 15 35.4000
+7 bb 126 36.5000
+7 bb 126 36.5000
+3 bb 40 36.5000
+3 aa 92 35.4000
+explain select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 20 Using where
+2 DERIVED t2 ALL NULL NULL NULL NULL 20 Using where; Using temporary
+explain format=json select * from (select a, c,
+sum(b) over (partition by a,c) as sum_b,
+avg(b) over (partition by c) as avg_b
+from t2 ) as t
+where t.a > 2 and t.c in ('aa','bb','cc');
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 20,
+ "filtered": 100,
+ "attached_condition": "t.a > 2 and t.c in ('aa','bb','cc')",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "window_functions_computation": {
+ "sorts": {
+ "filesort": {
+ "sort_key": "t2.c"
+ },
+ "filesort": {
+ "sort_key": "t2.a, t2.c"
+ }
+ },
+ "temporary_table": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 20,
+ "filtered": 100,
+ "attached_condition": "t2.c in ('aa','bb','cc')"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
drop table t1,t2;
set optimizer_switch= @save_optimizer_switch;
#
diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test
index f82b23a9aa1..f7bdee51206 100644
--- a/mysql-test/t/derived_cond_pushdown.test
+++ b/mysql-test/t/derived_cond_pushdown.test
@@ -1617,6 +1617,42 @@ eval $q4;
eval explain $q4;
eval explain format=json $q4;
+let $q5=
+select * from (select a, c,
+ sum(b) over (partition by a,c) as sum_b,
+ avg(b) over (partition by a,c) as avg_b
+ from t2 ) as t
+ where t.a > 2 and t.c in ('aa','bb','cc');
+
+eval $no_pushdown $q5;
+eval $q5;
+eval explain $q5;
+eval explain format=json $q5;
+
+let $q6=
+select * from (select a, c,
+ sum(b) over (partition by a,c) as sum_b,
+ avg(b) over (partition by a) as avg_b
+ from t2 ) as t
+ where t.a > 2 and t.c in ('aa','bb','cc');
+
+eval $no_pushdown $q6;
+eval $q6;
+eval explain $q6;
+eval explain format=json $q6;
+
+let $q7=
+select * from (select a, c,
+ sum(b) over (partition by a,c) as sum_b,
+ avg(b) over (partition by c) as avg_b
+ from t2 ) as t
+ where t.a > 2 and t.c in ('aa','bb','cc');
+
+eval $no_pushdown $q7;
+eval $q7;
+eval explain $q7;
+eval explain format=json $q7;
+
drop table t1,t2;
set optimizer_switch= @save_optimizer_switch;
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index ad18e1c4686..bf1a777f50c 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -1251,8 +1251,9 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
{
if (sl->join->group_list || sl->join->implicit_grouping)
continue;
- if (!(sl->window_specs.elements == 1 &&
- sl->window_specs.head()->partition_list))
+ ORDER *common_partition_fields=
+ sl->find_common_window_func_partition_fields(thd);
+ if (!common_partition_fields)
continue;
extracted_cond_copy= !sl->next_select() ?
extracted_cond :
@@ -1260,9 +1261,8 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!extracted_cond_copy)
continue;
- Item *cond_over_partition_fields;
- ORDER *grouping_list= sl->window_specs.head()->partition_list->first;
- sl->collect_grouping_fields(thd, grouping_list);
+ Item *cond_over_partition_fields;;
+ sl->collect_grouping_fields(thd, common_partition_fields);
sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
derived);
cond_over_partition_fields=
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 79f2b111f20..e7bb084d134 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1246,6 +1246,7 @@ public:
}
bool have_window_funcs() const { return (window_funcs.elements !=0); }
+ ORDER *find_common_window_func_partition_fields(THD *thd);
bool cond_pushdown_is_allowed() const
{ return !olap && !explicit_limit; }
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 74e1ad25183..7586bd78fe1 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -1,3 +1,4 @@
+#include "sql_parse.h"
#include "sql_select.h"
#include "sql_list.h"
#include "item_windowfunc.h"
@@ -307,6 +308,83 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
DBUG_RETURN(0);
}
+
+/**
+ @brief
+ Find fields common for all partition lists used in window functions
+
+ @param thd The thread handle
+
+ @details
+ This function looks for the field references in the partition lists
+ of all window functions used in this select that are common for
+ all the partition lists. The function returns an ORDER list contained
+ all such references.The list either is specially built by the function
+ or is taken directly from the first window specification.
+
+ @retval
+ pointer to the first element of the ORDER list contained field
+ references common for all partition lists
+ 0 if no such reference is found.
+*/
+
+ORDER *st_select_lex::find_common_window_func_partition_fields(THD *thd)
+{
+ ORDER *ord;
+ Item *item;
+ DBUG_ASSERT(window_funcs.elements);
+ List_iterator_fast<Item_window_func> it(window_funcs);
+ Item_window_func *wf= it++;
+ if (!wf->window_spec->partition_list)
+ return 0;
+ List<Item> common_fields;
+ uint first_partition_elements;
+ for (ord= wf->window_spec->partition_list->first; ord; ord= ord->next)
+ {
+ if ((*ord->item)->real_item()->type() == Item::FIELD_ITEM)
+ common_fields.push_back(*ord->item, thd->mem_root);
+ first_partition_elements++;
+ }
+ if (window_specs.elements == 1 &&
+ common_fields.elements == first_partition_elements)
+ return wf->window_spec->partition_list->first;
+ List_iterator<Item> li(common_fields);
+ while (common_fields.elements && (wf= it++))
+ {
+ if (!wf->window_spec->partition_list)
+ return 0;
+ while ((item= li++))
+ {
+ for (ord= wf->window_spec->partition_list->first; ord; ord= ord->next)
+ {
+ if (item->eq(*ord->item, false))
+ break;
+ }
+ if (!ord)
+ li.remove();
+ }
+ li.rewind();
+ }
+ if (!common_fields.elements)
+ return 0;
+ if (common_fields.elements == first_partition_elements)
+ return wf->window_spec->partition_list->first;
+ SQL_I_List<ORDER> res_list;
+ it.rewind();
+ wf= it++;
+ for (ord= wf->window_spec->partition_list->first, item= li++;
+ ord; ord= ord->next)
+ {
+ if (item != *ord->item)
+ continue;
+ if (add_to_list(thd, res_list, item, ord->direction))
+ return 0;
+ item= li++;
+ }
+ return res_list.first;
+}
+
+
/////////////////////////////////////////////////////////////////////////////
// Sorting window functions to minimize the number of table scans
// performed during the computation of these functions