Commit 9bd194b1 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-9848: Window functions: reuse sorting and/or scanning

- Rename Window_funcs_computation to Window_funcs_computation_step
- Introduce Window_func_sort which invokes filesort and then
  invokes computation of all window functions that use this ordering.
- Expose Window functions' sort operations in EXPLAIN|ANALYZE FORMAT=JSON
parent e30bd913
...@@ -1412,6 +1412,11 @@ EXPLAIN ...@@ -1412,6 +1412,11 @@ EXPLAIN
"query_block": { "query_block": {
"select_id": 1, "select_id": 1,
"window_functions_computation": { "window_functions_computation": {
"sorts": {
"filesort": {
"sort_key": "t0.a"
}
},
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t0", "table_name": "t0",
...@@ -1438,6 +1443,11 @@ EXPLAIN ...@@ -1438,6 +1443,11 @@ EXPLAIN
"filesort": { "filesort": {
"sort_key": "t1.a", "sort_key": "t1.a",
"window_functions_computation": { "window_functions_computation": {
"sorts": {
"filesort": {
"sort_key": "sum(t1.b)"
}
},
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t1", "table_name": "t1",
...@@ -1462,6 +1472,11 @@ EXPLAIN ...@@ -1462,6 +1472,11 @@ EXPLAIN
"query_block": { "query_block": {
"select_id": 1, "select_id": 1,
"window_functions_computation": { "window_functions_computation": {
"sorts": {
"filesort": {
"sort_key": "sum(t1.b)"
}
},
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t1", "table_name": "t1",
...@@ -1491,6 +1506,11 @@ EXPLAIN ...@@ -1491,6 +1506,11 @@ EXPLAIN
"filesort": { "filesort": {
"sort_key": "t1.b", "sort_key": "t1.b",
"window_functions_computation": { "window_functions_computation": {
"sorts": {
"filesort": {
"sort_key": "t1.b"
}
},
"temporary_table": { "temporary_table": {
"table": { "table": {
"table_name": "t1", "table_name": "t1",
...@@ -1580,3 +1600,97 @@ NULL NULL 24 1.0000 NULL ...@@ -1580,3 +1600,97 @@ NULL NULL 24 1.0000 NULL
NULL NULL 38 1.0000 NULL NULL NULL 38 1.0000 NULL
NULL NULL 42 1.0000 NULL NULL NULL 42 1.0000 NULL
drop table t1; drop table t1;
#
# MDEV-9848: Window functions: reuse sorting and/or scanning
#
create table t1 (a int, b int, c int);
insert into t1 values
(1,3,1),
(2,2,1),
(3,1,1);
# Check using counters
flush status;
select
rank() over (partition by c order by a),
rank() over (partition by c order by b)
from t1;
rank() over (partition by c order by a) rank() over (partition by c order by b)
1 3
2 2
3 1
show status like '%sort%';
Variable_name Value
Sort_merge_passes 0
Sort_priority_queue_sorts 0
Sort_range 0
Sort_rows 6
Sort_scan 2
flush status;
select
rank() over (partition by c order by a),
rank() over (partition by c order by a)
from t1;
rank() over (partition by c order by a) rank() over (partition by c order by a)
1 1
2 2
3 3
show status like '%sort%';
Variable_name Value
Sort_merge_passes 0
Sort_priority_queue_sorts 0
Sort_range 0
Sort_rows 3
Sort_scan 1
explain format=json
select
rank() over (partition by c order by a),
rank() over (partition by c order by a)
from t1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"window_functions_computation": {
"sorts": {
"filesort": {
"sort_key": "t1.c, t1.a"
}
},
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 3,
"filtered": 100
}
}
}
}
}
explain format=json
select
rank() over (order by a),
row_number() over (order by a)
from t1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"window_functions_computation": {
"sorts": {
"filesort": {
"sort_key": "t1.a"
}
},
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 3,
"filtered": 100
}
}
}
}
}
drop table t1;
...@@ -1014,3 +1014,52 @@ window w1 as (partition by a order by b,pk), ...@@ -1014,3 +1014,52 @@ window w1 as (partition by a order by b,pk),
drop table t1; drop table t1;
--echo #
--echo # MDEV-9848: Window functions: reuse sorting and/or scanning
--echo #
create table t1 (a int, b int, c int);
insert into t1 values
(1,3,1),
(2,2,1),
(3,1,1);
--echo # Check using counters
flush status;
select
rank() over (partition by c order by a),
rank() over (partition by c order by b)
from t1;
show status like '%sort%';
flush status;
select
rank() over (partition by c order by a),
rank() over (partition by c order by a)
from t1;
show status like '%sort%';
# Check using EXPLAIN FORMAT=JSON
explain format=json
select
rank() over (partition by c order by a),
rank() over (partition by c order by a)
from t1;
explain format=json
select
rank() over (order by a),
row_number() over (order by a)
from t1;
--disable_parsing
explain format=json
select
rank() over (partition by c order by a),
count(*) over (partition by c)
from t1;
--enable_parsing
drop table t1;
...@@ -885,8 +885,12 @@ void Explain_select::print_explain_json(Explain_query *query, ...@@ -885,8 +885,12 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->add_member("duplicate_removal").start_object(); writer->add_member("duplicate_removal").start_object();
break; break;
case AGGR_OP_WINDOW_FUNCS: case AGGR_OP_WINDOW_FUNCS:
{
//TODO: make print_json_members virtual?
writer->add_member("window_functions_computation").start_object(); writer->add_member("window_functions_computation").start_object();
((Explain_aggr_window_funcs*)node)->print_json_members(writer, is_analyze);
break; break;
}
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
...@@ -905,15 +909,21 @@ void Explain_select::print_explain_json(Explain_query *query, ...@@ -905,15 +909,21 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->end_object(); writer->end_object();
} }
void Explain_aggr_filesort::init(THD *thd, Filesort *filesort)
Explain_aggr_filesort::Explain_aggr_filesort(MEM_ROOT *mem_root,
bool is_analyze,
Filesort *filesort)
: tracker(is_analyze)
{ {
child= NULL;
for (ORDER *ord= filesort->order; ord; ord= ord->next) for (ORDER *ord= filesort->order; ord; ord= ord->next)
{ {
sort_items.push_back(ord->item[0], thd->mem_root); sort_items.push_back(ord->item[0], mem_root);
} }
filesort->tracker= &tracker; filesort->tracker= &tracker;
} }
void Explain_aggr_filesort::print_json_members(Json_writer *writer, void Explain_aggr_filesort::print_json_members(Json_writer *writer,
bool is_analyze) bool is_analyze)
{ {
...@@ -941,6 +951,23 @@ void Explain_aggr_filesort::print_json_members(Json_writer *writer, ...@@ -941,6 +951,23 @@ void Explain_aggr_filesort::print_json_members(Json_writer *writer,
tracker.print_json_members(writer); tracker.print_json_members(writer);
} }
void Explain_aggr_window_funcs::print_json_members(Json_writer *writer,
bool is_analyze)
{
Explain_aggr_filesort *srt;
List_iterator<Explain_aggr_filesort> it(sorts);
writer->add_member("sorts").start_object();
while ((srt= it++))
{
writer->add_member("filesort").start_object();
srt->print_json_members(writer, is_analyze);
writer->end_object(); // filesort
}
writer->end_object(); // sorts
}
void Explain_basic_join::print_explain_json(Explain_query *query, void Explain_basic_join::print_explain_json(Explain_query *query,
Json_writer *writer, Json_writer *writer,
bool is_analyze) bool is_analyze)
......
...@@ -279,19 +279,16 @@ class Explain_aggr_node : public Sql_alloc ...@@ -279,19 +279,16 @@ class Explain_aggr_node : public Sql_alloc
Explain_aggr_node *child; Explain_aggr_node *child;
}; };
class Explain_aggr_filesort : public Explain_aggr_node class Explain_aggr_filesort : public Explain_aggr_node
{ {
List<Item> sort_items; List<Item> sort_items;
public: public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_FILESORT; } enum_explain_aggr_node_type get_type() { return AGGR_OP_FILESORT; }
Filesort_tracker tracker; Filesort_tracker tracker;
Explain_aggr_filesort(bool is_analyze) : tracker(is_analyze) Explain_aggr_filesort(MEM_ROOT *mem_root, bool is_analyze,
{ Filesort *filesort);
child= NULL;
}
void init(THD* thd, Filesort *filesort);
void print_json_members(Json_writer *writer, bool is_analyze); void print_json_members(Json_writer *writer, bool is_analyze);
}; };
...@@ -309,8 +306,12 @@ class Explain_aggr_remove_dups : public Explain_aggr_node ...@@ -309,8 +306,12 @@ class Explain_aggr_remove_dups : public Explain_aggr_node
class Explain_aggr_window_funcs : public Explain_aggr_node class Explain_aggr_window_funcs : public Explain_aggr_node
{ {
List<Explain_aggr_filesort> sorts;
public: public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_WINDOW_FUNCS; } enum_explain_aggr_node_type get_type() { return AGGR_OP_WINDOW_FUNCS; }
void print_json_members(Json_writer *writer, bool is_analyze);
friend class Window_funcs_computation_step;
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
......
...@@ -451,6 +451,11 @@ class base_list_iterator ...@@ -451,6 +451,11 @@ class base_list_iterator
el= &current->next; el= &current->next;
return current->info; return current->info;
} }
/* Get what calling next() would return, without moving the iterator */
inline void *peek()
{
return (*el)->info;
}
inline void *next_fast(void) inline void *next_fast(void)
{ {
list_node *tmp; list_node *tmp;
...@@ -503,6 +508,10 @@ class base_list_iterator ...@@ -503,6 +508,10 @@ class base_list_iterator
{ {
return el == &list->last_ref()->next; return el == &list->last_ref()->next;
} }
inline bool at_end()
{
return current == &end_of_list;
}
friend class error_list_iterator; friend class error_list_iterator;
}; };
...@@ -550,6 +559,7 @@ template <class T> class List_iterator :public base_list_iterator ...@@ -550,6 +559,7 @@ template <class T> class List_iterator :public base_list_iterator
List_iterator() : base_list_iterator() {} List_iterator() : base_list_iterator() {}
inline void init(List<T> &a) { base_list_iterator::init(a); } inline void init(List<T> &a) { base_list_iterator::init(a); }
inline T* operator++(int) { return (T*) base_list_iterator::next(); } inline T* operator++(int) { return (T*) base_list_iterator::next(); }
inline T* peek() { return (T*) base_list_iterator::peek(); }
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); } inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
inline void rewind(void) { base_list_iterator::rewind(); } inline void rewind(void) { base_list_iterator::rewind(); }
......
...@@ -2661,7 +2661,7 @@ bool JOIN::make_aggr_tables_info() ...@@ -2661,7 +2661,7 @@ bool JOIN::make_aggr_tables_info()
curr_tab= join_tab + top_join_tab_count + aggr_tables - 1; curr_tab= join_tab + top_join_tab_count + aggr_tables - 1;
if (select_lex->window_funcs.elements) if (select_lex->window_funcs.elements)
{ {
curr_tab->window_funcs_step= new Window_funcs_computation; curr_tab->window_funcs_step= new Window_funcs_computation_step;
if (curr_tab->window_funcs_step->setup(thd, &select_lex->window_funcs, if (curr_tab->window_funcs_step->setup(thd, &select_lex->window_funcs,
curr_tab)) curr_tab))
DBUG_RETURN(true); DBUG_RETURN(true);
...@@ -23766,8 +23766,9 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, ...@@ -23766,8 +23766,9 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
if (filesort) if (filesort)
{ {
eta->pre_join_sort= new Explain_aggr_filesort(thd->lex->analyze_stmt); eta->pre_join_sort= new Explain_aggr_filesort(thd->mem_root,
eta->pre_join_sort->init(thd, filesort); thd->lex->analyze_stmt,
filesort);
} }
tracker= &eta->tracker; tracker= &eta->tracker;
...@@ -24183,6 +24184,8 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) ...@@ -24183,6 +24184,8 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
JOIN_TAB *join_tab=join->join_tab + join->top_join_tab_count; JOIN_TAB *join_tab=join->join_tab + join->top_join_tab_count;
Explain_aggr_node *prev_node; Explain_aggr_node *prev_node;
Explain_aggr_node *node= xpl_sel->aggr_tree; Explain_aggr_node *node= xpl_sel->aggr_tree;
bool is_analyze= join->thd->lex->analyze_stmt;
THD *thd= join->thd;
for (uint i= 0; i < join->aggr_tables; i++, join_tab++) for (uint i= 0; i < join->aggr_tables; i++, join_tab++)
{ {
...@@ -24193,9 +24196,15 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) ...@@ -24193,9 +24196,15 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
if (join_tab->window_funcs_step) if (join_tab->window_funcs_step)
{ {
prev_node=node; Explain_aggr_node *new_node=
node= new Explain_aggr_window_funcs; join_tab->window_funcs_step->save_explain_plan(thd->mem_root,
node->child= prev_node; is_analyze);
if (new_node)
{
prev_node=node;
node= new_node;
node->child= prev_node;
}
} }
/* The below matches execution in join_init_read_record() */ /* The below matches execution in join_init_read_record() */
...@@ -24208,10 +24217,8 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) ...@@ -24208,10 +24217,8 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
if (join_tab->filesort) if (join_tab->filesort)
{ {
bool is_analyze= join->thd->lex->analyze_stmt; Explain_aggr_filesort *eaf =
Explain_aggr_filesort *eaf = new Explain_aggr_filesort(is_analyze); new Explain_aggr_filesort(thd->mem_root, is_analyze, join_tab->filesort);
eaf->init(join->thd, join_tab->filesort);
prev_node= node; prev_node= node;
node= eaf; node= eaf;
node->child= prev_node; node->child= prev_node;
......
...@@ -428,7 +428,7 @@ typedef struct st_join_table { ...@@ -428,7 +428,7 @@ typedef struct st_join_table {
Non-NULL value means this join_tab must do window function computation Non-NULL value means this join_tab must do window function computation
before reading. before reading.
*/ */
Window_funcs_computation* window_funcs_step; Window_funcs_computation_step* window_funcs_step;
/** /**
List of topmost expressions in the select list. The *next* JOIN TAB List of topmost expressions in the select list. The *next* JOIN TAB
......
...@@ -440,7 +440,19 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1, ...@@ -440,7 +440,19 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
typedef int (*Item_window_func_cmp)(Item_window_func *f1, typedef int (*Item_window_func_cmp)(Item_window_func *f1,
Item_window_func *f2, Item_window_func *f2,
void *arg); void *arg);
/*
@brief
Sort window functions so that those that can be computed together are
adjacent.
@detail
Sort window functions by their
- required sorting order,
- partition list,
- window frame compatibility.
The changes between the groups are marked by setting item_window_func->marker.
*/
static static
void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list) void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list)
...@@ -479,7 +491,9 @@ void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list) ...@@ -479,7 +491,9 @@ void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list)
FRAME_CHANGE_FLAG; FRAME_CHANGE_FLAG;
} }
else if (win_spec_prev->partition_list != win_spec_curr->partition_list) else if (win_spec_prev->partition_list != win_spec_curr->partition_list)
{
curr->marker|= PARTITION_CHANGE_FLAG | FRAME_CHANGE_FLAG; curr->marker|= PARTITION_CHANGE_FLAG | FRAME_CHANGE_FLAG;
}
} }
else if (win_spec_prev->window_frame != win_spec_curr->window_frame) else if (win_spec_prev->window_frame != win_spec_curr->window_frame)
curr->marker|= FRAME_CHANGE_FLAG; curr->marker|= FRAME_CHANGE_FLAG;
...@@ -1720,14 +1734,6 @@ static ORDER* concat_order_lists(MEM_ROOT *mem_root, ORDER *list1, ORDER *list2) ...@@ -1720,14 +1734,6 @@ static ORDER* concat_order_lists(MEM_ROOT *mem_root, ORDER *list1, ORDER *list2)
bool Window_func_runner::setup(THD *thd) bool Window_func_runner::setup(THD *thd)
{ {
Window_spec *spec = win_func->window_spec;
ORDER* sort_order= concat_order_lists(thd->mem_root,
spec->partition_list->first,
spec->order_list->first);
filesort= new (thd->mem_root) Filesort(sort_order, HA_POS_ERROR, NULL);
filesort->tracker= new Filesort_tracker(thd->lex->analyze_stmt);
win_func->setup_partition_border_check(thd); win_func->setup_partition_border_check(thd);
Item_sum::Sumfunctype type= win_func->window_func()->sum_func(); Item_sum::Sumfunctype type= win_func->window_func()->sum_func();
...@@ -1770,47 +1776,88 @@ bool Window_func_runner::setup(THD *thd) ...@@ -1770,47 +1776,88 @@ bool Window_func_runner::setup(THD *thd)
/* /*
Compute the value of window function for all rows. Compute the value of window function for all rows.
*/ */
bool Window_func_runner::exec(JOIN *join) bool Window_func_runner::exec(TABLE *tbl, SORT_INFO *filesort_result)
{ {
THD *thd= join->thd; THD *thd= current_thd;
JOIN_TAB *join_tab= &join->join_tab[join->top_join_tab_count];
if (create_sort_index(thd, join, join_tab,
filesort))
return true;
win_func->set_phase_to_computation(); win_func->set_phase_to_computation();
/* /* Go through the sorted array and compute the window function */
Go through the sorted array and compute the window function
*/
READ_RECORD info; READ_RECORD info;
TABLE *tbl= join_tab->table;
if (init_read_record(&info, thd, tbl, NULL/*select*/, join_tab->filesort_result, if (init_read_record(&info, thd, tbl, NULL/*select*/, filesort_result,
0, 1, FALSE)) 0, 1, FALSE))
return true; return true;
bool is_error= compute_func(win_func, tbl, &info); bool is_error= compute_func(win_func, tbl, &info);
/* This calls filesort_free_buffers(): */
end_read_record(&info);
delete join_tab->filesort_result;
join_tab->filesort_result= NULL;
win_func->set_phase_to_retrieval(); win_func->set_phase_to_retrieval();
end_read_record(&info);
return is_error; return is_error;
} }
bool Window_funcs_computation::setup(THD *thd, bool Window_func_sort::exec(JOIN *join)
List<Item_window_func> *window_funcs,
JOIN_TAB *tab)
{ {
List_iterator_fast<Item_window_func> it(*window_funcs); THD *thd= join->thd;
Item_window_func *item_win; JOIN_TAB *join_tab= &join->join_tab[join->top_join_tab_count];
if (create_sort_index(thd, join, join_tab, filesort))
return true;
TABLE *tbl= join_tab->table;
SORT_INFO *filesort_result= join_tab->filesort_result;
bool is_error= false;
List_iterator<Window_func_runner> it(runners);
Window_func_runner *runner; Window_func_runner *runner;
while ((runner= it++))
{
if ((is_error= runner->exec(tbl, filesort_result)))
break;
}
delete join_tab->filesort_result;
join_tab->filesort_result= NULL;
return is_error;
}
bool Window_func_sort::setup(THD *thd, SQL_SELECT *sel,
List_iterator<Item_window_func> &it)
{
Item_window_func *win_func= it.peek();
Window_spec *spec = win_func->window_spec;
ORDER* sort_order= concat_order_lists(thd->mem_root,
spec->partition_list->first,
spec->order_list->first);
filesort= new (thd->mem_root) Filesort(sort_order, HA_POS_ERROR, NULL);
/* Apply the same condition that the subsequent sort has. */
filesort->select= sel;
do
{
Window_func_runner *runner;
if (!(runner= new Window_func_runner(win_func)) ||
runner->setup(thd))
{
return true;
}
runners.push_back(runner);
it++;
} while ((win_func= it.peek()) && !(win_func->marker & SORTORDER_CHANGE_FLAG));
return false;
}
bool Window_funcs_computation_step::setup(THD *thd,
List<Item_window_func> *window_funcs,
JOIN_TAB *tab)
{
order_window_funcs_by_window_specs(window_funcs); order_window_funcs_by_window_specs(window_funcs);
SQL_SELECT *sel= NULL; SQL_SELECT *sel= NULL;
...@@ -1820,46 +1867,61 @@ bool Window_funcs_computation::setup(THD *thd, ...@@ -1820,46 +1867,61 @@ bool Window_funcs_computation::setup(THD *thd,
DBUG_ASSERT(!sel->quick); DBUG_ASSERT(!sel->quick);
} }
// for each window function Window_func_sort *srt;
while ((item_win= it++)) List_iterator<Item_window_func> iter(*window_funcs);
while (iter.peek())
{ {
// Create a runner and call setup for it if (!(srt= new Window_func_sort()) ||
if (!(runner= new Window_func_runner(item_win)) || srt->setup(thd, sel, iter))
runner->setup(thd))
{ {
return true; return true;
} }
/* Apply the same condition that the subsequent sort will */ win_func_sorts.push_back(srt, thd->mem_root);
runner->filesort->select= sel;
win_func_runners.push_back(runner, thd->mem_root);
} }
return false; return false;
} }
bool Window_funcs_computation::exec(JOIN *join) bool Window_funcs_computation_step::exec(JOIN *join)
{ {
List_iterator<Window_func_runner> it(win_func_runners); List_iterator<Window_func_sort> it(win_func_sorts);
Window_func_runner *runner; Window_func_sort *srt;
/* Execute each runner */ /* Execute each sort */
while ((runner = it++)) while ((srt = it++))
{ {
if (runner->exec(join)) if (srt->exec(join))
return true; return true;
} }
return false; return false;
} }
void Window_funcs_computation::cleanup() void Window_funcs_computation_step::cleanup()
{ {
List_iterator<Window_func_runner> it(win_func_runners); List_iterator<Window_func_sort> it(win_func_sorts);
Window_func_runner *runner; Window_func_sort *srt;
while ((runner = it++)) while ((srt = it++))
{
srt->cleanup();
delete srt;
}
}
Explain_aggr_window_funcs*
Window_funcs_computation_step::save_explain_plan(MEM_ROOT *mem_root,
bool is_analyze)
{
Explain_aggr_window_funcs *xpl= new Explain_aggr_window_funcs;
List_iterator<Window_func_sort> it(win_func_sorts);
Window_func_sort *srt;
while ((srt = it++))
{ {
runner->cleanup(); Explain_aggr_filesort *eaf=
delete runner; new Explain_aggr_filesort(mem_root, is_analyze, srt->filesort);
xpl->sorts.push_back(eaf, mem_root);
} }
return xpl;
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
......
...@@ -166,12 +166,10 @@ typedef bool (*window_compute_func_t)(Item_window_func *item_win, ...@@ -166,12 +166,10 @@ typedef bool (*window_compute_func_t)(Item_window_func *item_win,
class Window_func_runner : public Sql_alloc class Window_func_runner : public Sql_alloc
{ {
Item_window_func *win_func; Item_window_func *win_func;
/* Window function can be computed over this sorting */
Filesort *filesort;
/* The function to use for computation*/ /* The function to use for computation*/
window_compute_func_t compute_func; window_compute_func_t compute_func;
public: public:
Window_func_runner(Item_window_func *win_func_arg) : Window_func_runner(Item_window_func *win_func_arg) :
win_func(win_func_arg) win_func(win_func_arg)
...@@ -181,14 +179,33 @@ class Window_func_runner : public Sql_alloc ...@@ -181,14 +179,33 @@ class Window_func_runner : public Sql_alloc
bool setup(THD *thd); bool setup(THD *thd);
// This sorts and runs the window function. // This sorts and runs the window function.
bool exec(JOIN *join); bool exec(TABLE *tbl, SORT_INFO *filesort_result);
};
/*
Represents a group of window functions that require the same sorting of
rows and so share the filesort() call.
*/
class Window_func_sort : public Sql_alloc
{
List<Window_func_runner> runners;
/* Window functions can be computed over this sorting */
Filesort *filesort;
public:
bool setup(THD *thd, SQL_SELECT *sel, List_iterator<Item_window_func> &it);
bool exec(JOIN *join);
void cleanup() { delete filesort; } void cleanup() { delete filesort; }
friend class Window_funcs_computation; friend class Window_funcs_computation_step;
}; };
struct st_join_table; struct st_join_table;
class Explain_aggr_window_funcs;
/* /*
This is a "window function computation phase": a single object of this class This is a "window function computation phase": a single object of this class
takes care of computing all window functions in a SELECT. takes care of computing all window functions in a SELECT.
...@@ -198,12 +215,14 @@ struct st_join_table; ...@@ -198,12 +215,14 @@ struct st_join_table;
temporary table. temporary table.
*/ */
class Window_funcs_computation : public Sql_alloc class Window_funcs_computation_step : public Sql_alloc
{ {
List<Window_func_runner> win_func_runners; List<Window_func_sort> win_func_sorts;
public: public:
bool setup(THD *thd, List<Item_window_func> *window_funcs, st_join_table *tab); bool setup(THD *thd, List<Item_window_func> *window_funcs, st_join_table *tab);
bool exec(JOIN *join); bool exec(JOIN *join);
Explain_aggr_window_funcs *save_explain_plan(MEM_ROOT *mem_root, bool is_analyze);
void cleanup(); void cleanup();
}; };
......
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