mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Moved window function computation code from JOIN::exec_inner() into
a separate function, JOIN::process_window_functions().
This commit is contained in:
@ -3235,6 +3235,7 @@ void JOIN::exec_inner()
|
|||||||
error= thd->is_error();
|
error= thd->is_error();
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
process_window_functions(curr_fields_list);
|
||||||
|
|
||||||
THD_STAGE_INFO(thd, stage_sending_data);
|
THD_STAGE_INFO(thd, stage_sending_data);
|
||||||
DBUG_PRINT("info", ("%s", thd->proc_info));
|
DBUG_PRINT("info", ("%s", thd->proc_info));
|
||||||
|
@ -1518,6 +1518,9 @@ public:
|
|||||||
int reinit();
|
int reinit();
|
||||||
int init_execution();
|
int init_execution();
|
||||||
void exec();
|
void exec();
|
||||||
|
|
||||||
|
void process_window_functions(List<Item> *curr_fields_list);
|
||||||
|
|
||||||
void exec_inner();
|
void exec_inner();
|
||||||
bool prepare_result(List<Item> **columns_list);
|
bool prepare_result(List<Item> **columns_list);
|
||||||
int destroy();
|
int destroy();
|
||||||
@ -2291,4 +2294,5 @@ public:
|
|||||||
int execute(JOIN *join);
|
int execute(JOIN *join);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool test_if_order_compatible(SQL_I_List<ORDER> &a, SQL_I_List<ORDER> &b);
|
||||||
#endif /* SQL_SELECT_INCLUDED */
|
#endif /* SQL_SELECT_INCLUDED */
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "sql_select.h"
|
#include "sql_select.h"
|
||||||
|
#include "item_windowfunc.h"
|
||||||
|
#include "filesort.h"
|
||||||
#include "sql_window.h"
|
#include "sql_window.h"
|
||||||
|
|
||||||
|
|
||||||
@ -77,3 +79,140 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
|
|||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief
|
||||||
|
This function is called by JOIN::exec to compute window function values
|
||||||
|
|
||||||
|
@detail
|
||||||
|
JOIN::exec calls this after it has filled the temporary table with query
|
||||||
|
output. The temporary table has fields to store window function values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void JOIN::process_window_functions(List<Item> *curr_fields_list)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
TODO Get this code to set can_compute_window_function during preparation,
|
||||||
|
not during execution.
|
||||||
|
|
||||||
|
The reason for this is the following:
|
||||||
|
Our single scan optimization for window functions without tmp table,
|
||||||
|
is valid, if and only if, we only need to perform one sorting operation,
|
||||||
|
via filesort. The cases where we need to perform one sorting operation only:
|
||||||
|
|
||||||
|
* A select with only one window function.
|
||||||
|
* A select with multiple window functions, but they must have their
|
||||||
|
partition and order by clauses compatible. This means that one ordering
|
||||||
|
is acceptable for both window functions.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
partition by a, b, c; order by d, e results in sorting by a b c d e.
|
||||||
|
partition by a; order by d results in sorting by a d.
|
||||||
|
|
||||||
|
This kind of sorting is compatible. The less specific partition does
|
||||||
|
not care for the order of b and c columns so it is valid if we sort
|
||||||
|
by those in case of equality over a.
|
||||||
|
|
||||||
|
partition by a, b; order by d, e results in sorting by a b d e
|
||||||
|
partition by a; order by e results in sorting by a e
|
||||||
|
|
||||||
|
This sorting is incompatible due to the order by clause. The partition by
|
||||||
|
clause is compatible, (partition by a) is a prefix for (partition by a, b)
|
||||||
|
However, order by e is not a prefix for order by d, e, thus it is not
|
||||||
|
compatible.
|
||||||
|
|
||||||
|
The rule for having compatible sorting is thus:
|
||||||
|
Each partition order must contain the other window functions partitions
|
||||||
|
prefixes, or be a prefix itself. This must hold true for all partitions.
|
||||||
|
Analog for the order by clause.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
List<Item_window_func> window_functions;
|
||||||
|
SQL_I_List<ORDER> largest_partition;
|
||||||
|
SQL_I_List<ORDER> largest_order_by;
|
||||||
|
List_iterator_fast<Item> it(*curr_fields_list);
|
||||||
|
bool can_compute_window_live = !need_tmp;
|
||||||
|
|
||||||
|
Item *item;
|
||||||
|
// Construct the window_functions item list and check if they can be
|
||||||
|
// computed using only one sorting.
|
||||||
|
//
|
||||||
|
// TODO: Perhaps group functions into compatible sorting bins
|
||||||
|
// to minimize the number of sorting passes required to compute all of them.
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
if (item->type() == Item::WINDOW_FUNC_ITEM)
|
||||||
|
{
|
||||||
|
Item_window_func *item_win = (Item_window_func *) item;
|
||||||
|
window_functions.push_back(item_win);
|
||||||
|
if (!can_compute_window_live)
|
||||||
|
continue; // No point checking since we have to perform multiple sorts.
|
||||||
|
Window_spec *spec = item_win->window_spec;
|
||||||
|
// Having an empty partition list on one window function and a
|
||||||
|
// not empty list on a separate window function causes the sorting
|
||||||
|
// to be incompatible.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// over (partition by a, order by x) && over (order by x).
|
||||||
|
//
|
||||||
|
// The first function requires an ordering by a first and then by x,
|
||||||
|
// while the seond function requires an ordering by x first.
|
||||||
|
// The same restriction is not required for the order by clause.
|
||||||
|
if (largest_partition.elements && !spec->partition_list.elements)
|
||||||
|
{
|
||||||
|
can_compute_window_live= FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
can_compute_window_live= test_if_order_compatible(largest_partition,
|
||||||
|
spec->partition_list);
|
||||||
|
if (!can_compute_window_live)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
can_compute_window_live= test_if_order_compatible(largest_order_by,
|
||||||
|
spec->order_list);
|
||||||
|
if (!can_compute_window_live)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (largest_partition.elements < spec->partition_list.elements)
|
||||||
|
largest_partition = spec->partition_list;
|
||||||
|
if (largest_order_by.elements < spec->order_list.elements)
|
||||||
|
largest_order_by = spec->order_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_compute_window_live && window_functions.elements && table_count == 1)
|
||||||
|
{
|
||||||
|
ha_rows examined_rows = 0;
|
||||||
|
ha_rows found_rows = 0;
|
||||||
|
ha_rows filesort_retval;
|
||||||
|
SORT_FIELD *s_order= (SORT_FIELD *) my_malloc(sizeof(SORT_FIELD) *
|
||||||
|
(largest_partition.elements + largest_order_by.elements) + 1,
|
||||||
|
MYF(MY_WME | MY_ZEROFILL | MY_THREAD_SPECIFIC));
|
||||||
|
|
||||||
|
size_t pos= 0;
|
||||||
|
for (ORDER* curr = largest_partition.first; curr; curr=curr->next, pos++)
|
||||||
|
s_order[pos].item = *curr->item;
|
||||||
|
|
||||||
|
for (ORDER* curr = largest_order_by.first; curr; curr=curr->next, pos++)
|
||||||
|
s_order[pos].item = *curr->item;
|
||||||
|
|
||||||
|
table[0]->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
|
||||||
|
MYF(MY_WME | MY_ZEROFILL|
|
||||||
|
MY_THREAD_SPECIFIC));
|
||||||
|
|
||||||
|
|
||||||
|
filesort_retval= filesort(thd, table[0], s_order,
|
||||||
|
(largest_partition.elements + largest_order_by.elements),
|
||||||
|
this->select, HA_POS_ERROR, FALSE,
|
||||||
|
&examined_rows, &found_rows,
|
||||||
|
this->explain->ops_tracker.report_sorting(thd));
|
||||||
|
table[0]->sort.found_records= filesort_retval;
|
||||||
|
|
||||||
|
join_tab->read_first_record = join_init_read_record;
|
||||||
|
join_tab->records= found_rows;
|
||||||
|
|
||||||
|
my_free(s_order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
#include "my_global.h"
|
#include "my_global.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Window functions module.
|
||||||
|
|
||||||
|
Each instance of window function has its own element in SELECT_LEX::window_specs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
class Window_frame_bound : public Sql_alloc
|
class Window_frame_bound : public Sql_alloc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user