Skip to content

Commit a2bafba

Browse files
committed
Make first_value and last_value computation efficient
With clever use of partition bounds, we only need to add one row to the items at a time. This way we remove the need to "reset" the item and run through the full partition again.
1 parent 15b8a77 commit a2bafba

File tree

2 files changed

+91
-16
lines changed

2 files changed

+91
-16
lines changed

sql/item_windowfunc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,8 @@ class Item_window_func : public Item_func_or_sum
657657
case Item_sum::PERCENT_RANK_FUNC:
658658
case Item_sum::CUME_DIST_FUNC:
659659
case Item_sum::NTILE_FUNC:
660+
case Item_sum::FIRST_VALUE_FUNC:
661+
case Item_sum::LAST_VALUE_FUNC:
660662
return true;
661663
default:
662664
return false;

sql/sql_window.cc

Lines changed: 89 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,17 @@ class Frame_cursor : public Sql_alloc
824824
}
825825
}
826826

827+
/* Clear all sum functions handled by this cursor. */
828+
void clear_sum_functions()
829+
{
830+
List_iterator_fast<Item_sum> iter_sum_func(sum_functions);
831+
Item_sum *sum_func;
832+
while ((sum_func= iter_sum_func++))
833+
{
834+
sum_func->clear();
835+
}
836+
}
837+
827838
/* Sum functions that this cursor handles. */
828839
List<Item_sum> sum_functions;
829840

@@ -1847,17 +1858,6 @@ class Frame_scan_cursor : public Frame_cursor
18471858
Table_read_cursor cursor;
18481859
ha_rows curr_rownum;
18491860

1850-
/* Clear all sum functions handled by this cursor. */
1851-
void clear_sum_functions()
1852-
{
1853-
List_iterator_fast<Item_sum> iter_sum_func(sum_functions);
1854-
Item_sum *sum_func;
1855-
while ((sum_func= iter_sum_func++))
1856-
{
1857-
sum_func->clear();
1858-
}
1859-
}
1860-
18611861
/* Scan the rows between the top bound and bottom bound. Add all the values
18621862
between them, top bound row and bottom bound row inclusive. */
18631863
void compute_values_for_current_row()
@@ -1883,6 +1883,55 @@ class Frame_scan_cursor : public Frame_cursor
18831883
}
18841884
};
18851885

1886+
/* A cursor that follows a target cursor. Each time a new row is added,
1887+
the window functions are cleared and only have the row at which the target
1888+
is point at added to them.
1889+
*/
1890+
class Frame_positional_cursor : public Frame_cursor
1891+
{
1892+
public:
1893+
Frame_positional_cursor(const Frame_cursor &position_cursor) :
1894+
position_cursor(position_cursor) {}
1895+
1896+
void init(READ_RECORD *info)
1897+
{
1898+
cursor.init(info);
1899+
}
1900+
1901+
void pre_next_partition(ha_rows rownum)
1902+
{
1903+
clear_sum_functions();
1904+
}
1905+
1906+
void next_partition(ha_rows rownum)
1907+
{
1908+
cursor.move_to(position_cursor.get_curr_rownum());
1909+
add_value_to_items();
1910+
}
1911+
1912+
void pre_next_row()
1913+
{
1914+
}
1915+
1916+
void next_row()
1917+
{
1918+
if (position_cursor.is_outside_computation_bounds())
1919+
clear_sum_functions();
1920+
1921+
cursor.move_to(position_cursor.get_curr_rownum());
1922+
add_value_to_items();
1923+
}
1924+
1925+
ha_rows get_curr_rownum() const
1926+
{
1927+
return position_cursor.get_curr_rownum();
1928+
}
1929+
1930+
private:
1931+
const Frame_cursor &position_cursor;
1932+
Table_read_cursor cursor;
1933+
};
1934+
18861935

18871936
/*
18881937
Get a Frame_cursor for a frame bound. This is a "factory function".
@@ -1990,8 +2039,9 @@ Frame_cursor *get_frame_cursor(THD *thd, Window_spec *spec, bool is_top_bound)
19902039
return NULL;
19912040
}
19922041

1993-
void add_extra_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
1994-
Item_window_func *window_func)
2042+
static
2043+
void add_special_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
2044+
Item_window_func *window_func)
19952045
{
19962046
Window_spec *spec= window_func->window_spec;
19972047
Item_sum *item_sum= window_func->window_func();
@@ -2010,6 +2060,19 @@ void add_extra_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
20102060
fc->add_sum_func(item_sum);
20112061
cursor_manager->add_cursor(fc);
20122062
break;
2063+
case Item_sum::FIRST_VALUE_FUNC:
2064+
fc= get_frame_cursor(thd, spec, true);
2065+
fc->set_no_action();
2066+
cursor_manager->add_cursor(fc);
2067+
fc= new Frame_positional_cursor(*fc);
2068+
fc->add_sum_func(item_sum);
2069+
cursor_manager->add_cursor(fc);
2070+
break;
2071+
case Item_sum::LAST_VALUE_FUNC:
2072+
fc= get_frame_cursor(thd, spec, false);
2073+
fc->add_sum_func(item_sum);
2074+
cursor_manager->add_cursor(fc);
2075+
break;
20132076
default:
20142077
fc= new Frame_unbounded_preceding(
20152078
thd, spec->partition_list, spec->order_list);
@@ -2032,6 +2095,8 @@ static bool is_computed_with_remove(Item_sum::Sumfunctype sum_func)
20322095
case Item_sum::RANK_FUNC:
20332096
case Item_sum::DENSE_RANK_FUNC:
20342097
case Item_sum::NTILE_FUNC:
2098+
case Item_sum::FIRST_VALUE_FUNC:
2099+
case Item_sum::LAST_VALUE_FUNC:
20352100
return false;
20362101
default:
20372102
return true;
@@ -2071,12 +2136,20 @@ void get_window_functions_required_cursors(
20712136

20722137
/*
20732138
If it is not a regular window function that follows frame specifications,
2074-
specific cursors are required. ROW_NUM, RANK, NTILE and others follow
2075-
such rules. Check is_frame_prohibited check for the full list.
2139+
and/or specific cursors are required. ROW_NUM, RANK, NTILE and others
2140+
follow such rules. Check is_frame_prohibited check for the full list.
2141+
2142+
TODO(cvicentiu) This approach is messy. Every time a function allows
2143+
computation in a certain way, we have to add an extra method to this
2144+
factory function. It is better to have window functions output
2145+
their own cursors, as needed. This way, the logic is bound
2146+
only to the implementation of said window function. Regular aggregate
2147+
functions can keep the default frame generating code, overwrite it or
2148+
add to it.
20762149
*/
20772150
if (item_win_func->is_frame_prohibited())
20782151
{
2079-
add_extra_frame_cursors(thd, cursor_manager, item_win_func);
2152+
add_special_frame_cursors(thd, cursor_manager, item_win_func);
20802153
cursor_managers->push_back(cursor_manager);
20812154
continue;
20822155
}

0 commit comments

Comments
 (0)