Skip to content

Commit

Permalink
MDEV-10059: Compute window functions with same sorting criteria simul…
Browse files Browse the repository at this point in the history
…taneously

Perform only one table scan for each window function present. We do this
by keeping keeping cursors for each window function frame bound and
running them for each function for every row.
  • Loading branch information
cvicentiu committed Sep 9, 2016
1 parent 19d24f0 commit 23e8b50
Show file tree
Hide file tree
Showing 4 changed files with 608 additions and 446 deletions.
43 changes: 11 additions & 32 deletions sql/item_windowfunc.cc
Expand Up @@ -41,7 +41,7 @@ Item_window_func::resolve_window_name(THD *thd)
return true;
}

return false;
return false;
}


Expand Down Expand Up @@ -154,38 +154,33 @@ void Item_window_func::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,


/*
This must be called before advance_window() can be called.
This must be called before attempting to compute the window function values.
@detail
If we attempt to do it in fix_fields(), partition_fields will refer
to the original window function arguments.
We need it to refer to temp.table columns.
*/

void Item_window_func::setup_partition_border_check(THD *thd)
{
partition_tracker.init(thd, window_spec->partition_list);
window_func()->setup_window_func(thd, window_spec);
}


void Item_sum_rank::setup_window_func(THD *thd, Window_spec *window_spec)
{
/* TODO: move this into Item_window_func? */
peer_tracker.init(thd, window_spec->order_list);
peer_tracker = new Group_bound_tracker(thd, window_spec->order_list);
peer_tracker->init();
clear();
}

void Item_sum_dense_rank::setup_window_func(THD *thd, Window_spec *window_spec)
{
/* TODO: consider moving this && Item_sum_rank's implementation */
peer_tracker.init(thd, window_spec->order_list);
peer_tracker = new Group_bound_tracker(thd, window_spec->order_list);
peer_tracker->init();
clear();
}

bool Item_sum_dense_rank::add()
{
if (peer_tracker.check_if_next_group() || first_add)
if (peer_tracker->check_if_next_group() || first_add)
{
first_add= false;
dense_rank++;
Expand All @@ -198,33 +193,18 @@ bool Item_sum_dense_rank::add()
bool Item_sum_rank::add()
{
row_number++;
if (peer_tracker.check_if_next_group())
if (peer_tracker->check_if_next_group())
{
/* Row value changed */
cur_rank= row_number;
}
return false;
}

bool Item_window_func::check_if_partition_changed()
{
return partition_tracker.check_if_next_group();
}

void Item_window_func::advance_window()
{
if (check_if_partition_changed())
{
/* Next partition */
window_func()->clear();
}
window_func()->add();
}

bool Item_sum_percent_rank::add()
{
row_number++;
if (peer_tracker.check_if_next_group())
if (peer_tracker->check_if_next_group())
{
/* Row value changed. */
cur_rank= row_number;
Expand All @@ -235,8 +215,7 @@ bool Item_sum_percent_rank::add()
void Item_sum_percent_rank::setup_window_func(THD *thd, Window_spec *window_spec)
{
/* TODO: move this into Item_window_func? */
peer_tracker.init(thd, window_spec->order_list);
peer_tracker = new Group_bound_tracker(thd, window_spec->order_list);
peer_tracker->init();
clear();
}


90 changes: 51 additions & 39 deletions sql/item_windowfunc.h
Expand Up @@ -12,25 +12,19 @@ int test_if_group_changed(List<Cached_item> &list);
/* A wrapper around test_if_group_changed */
class Group_bound_tracker
{
List<Cached_item> group_fields;
/*
During the first check_if_next_group, the list of cached_items is not
initialized. The compare function will return that the items match if
the field's value is the same as the Cached_item's default value (0).
This flag makes sure that we always return true during the first check.
XXX This is better to be implemented within test_if_group_changed, but
since it is used in other parts of the codebase, we keep it here for now.
*/
bool first_check;
public:
void init(THD *thd, SQL_I_List<ORDER> *list)

Group_bound_tracker(THD *thd, SQL_I_List<ORDER> *list)
{
for (ORDER *curr = list->first; curr; curr=curr->next)
{
Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE);
group_fields.push_back(tmp);
}
}

void init()
{
first_check= true;
}

Expand Down Expand Up @@ -76,6 +70,19 @@ class Group_bound_tracker
}
return 0;
}

private:
List<Cached_item> group_fields;
/*
During the first check_if_next_group, the list of cached_items is not
initialized. The compare function will return that the items match if
the field's value is the same as the Cached_item's default value (0).
This flag makes sure that we always return true during the first check.
XXX This is better to be implemented within test_if_group_changed, but
since it is used in other parts of the codebase, we keep it here for now.
*/
bool first_check;
};

/*
Expand All @@ -92,19 +99,22 @@ class Item_sum_row_number: public Item_sum_int
longlong count;

public:

Item_sum_row_number(THD *thd)
: Item_sum_int(thd), count(0) {}

void clear()
{
count= 0;
}
bool add()

bool add()
{
count++;
return false;
return false;
}
void update_field() {}

Item_sum_row_number(THD *thd)
: Item_sum_int(thd), count(0) {}
void update_field() {}

enum Sumfunctype sum_func() const
{
Expand All @@ -119,6 +129,7 @@ class Item_sum_row_number: public Item_sum_int
{
return "row_number(";
}

Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_sum_row_number>(thd, mem_root, this); }
};
Expand Down Expand Up @@ -146,9 +157,12 @@ class Item_sum_rank: public Item_sum_int
protected:
longlong row_number; // just ROW_NUMBER()
longlong cur_rank; // current value
Group_bound_tracker peer_tracker;

Group_bound_tracker *peer_tracker;
public:

Item_sum_rank(THD *thd) : Item_sum_int(thd), peer_tracker(NULL) {}

void clear()
{
/* This is called on partition start */
Expand All @@ -169,10 +183,6 @@ class Item_sum_rank: public Item_sum_int
TODO: ^^ what does this do ? It is not called ever?
*/

public:
Item_sum_rank(THD *thd)
: Item_sum_int(thd) {}

enum Sumfunctype sum_func () const
{
return RANK_FUNC;
Expand All @@ -184,9 +194,12 @@ class Item_sum_rank: public Item_sum_int
}

void setup_window_func(THD *thd, Window_spec *window_spec);

void cleanup()
{
peer_tracker.cleanup();
if (peer_tracker)
peer_tracker->cleanup();
delete peer_tracker;
Item_sum_int::cleanup();
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
Expand Down Expand Up @@ -217,7 +230,7 @@ class Item_sum_dense_rank: public Item_sum_int
{
longlong dense_rank;
bool first_add;
Group_bound_tracker peer_tracker;
Group_bound_tracker *peer_tracker;
public:
/*
XXX(cvicentiu) This class could potentially be implemented in the rank
Expand All @@ -236,7 +249,7 @@ class Item_sum_dense_rank: public Item_sum_int
}

Item_sum_dense_rank(THD *thd)
: Item_sum_int(thd), dense_rank(0), first_add(true) {}
: Item_sum_int(thd), dense_rank(0), first_add(true), peer_tracker(NULL) {}
enum Sumfunctype sum_func () const
{
return DENSE_RANK_FUNC;
Expand All @@ -251,7 +264,11 @@ class Item_sum_dense_rank: public Item_sum_int

void cleanup()
{
peer_tracker.cleanup();
if (peer_tracker)
{
peer_tracker->cleanup();
delete peer_tracker;
}
Item_sum_int::cleanup();
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
Expand Down Expand Up @@ -294,7 +311,7 @@ class Item_sum_percent_rank: public Item_sum_window_with_row_count
{
public:
Item_sum_percent_rank(THD *thd)
: Item_sum_window_with_row_count(thd), cur_rank(1) {}
: Item_sum_window_with_row_count(thd), cur_rank(1), peer_tracker(NULL) {}

longlong val_int()
{
Expand Down Expand Up @@ -354,11 +371,15 @@ class Item_sum_percent_rank: public Item_sum_window_with_row_count
longlong cur_rank; // Current rank of the current row.
longlong row_number; // Value if this were ROW_NUMBER() function.

Group_bound_tracker peer_tracker;
Group_bound_tracker *peer_tracker;

void cleanup()
{
peer_tracker.cleanup();
if (peer_tracker)
{
peer_tracker->cleanup();
delete peer_tracker;
}
Item_sum_num::cleanup();
}
};
Expand Down Expand Up @@ -515,12 +536,6 @@ class Item_window_func : public Item_func_or_sum
public:
Window_spec *window_spec;

/*
This stores the data about the partition we're currently in.
advance_window() uses this to tell when we've left one partition and
entered another
*/
Group_bound_tracker partition_tracker;
public:
Item_window_func(THD *thd, Item_sum *win_func, LEX_STRING *win_name)
: Item_func_or_sum(thd, (Item *) win_func),
Expand Down Expand Up @@ -613,9 +628,6 @@ class Item_window_func : public Item_func_or_sum
*/
void setup_partition_border_check(THD *thd);

void advance_window();
bool check_if_partition_changed();

enum_field_types field_type() const
{
return ((Item_sum *) args[0])->field_type();
Expand Down

0 comments on commit 23e8b50

Please sign in to comment.