summaryrefslogtreecommitdiff
path: root/sql/sql_window.cc
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <vicentiu@mariadb.org>2016-09-20 22:12:48 +0200
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2016-09-24 15:12:34 +0200
commita2bafbabe2c1335bd411daf85dde8908e55dab62 (patch)
treea7a08b9a3701d2f9aa23957a3bc5f7d58167b85d /sql/sql_window.cc
parent15b8a772ccd39bad6d391f7e49733730e0eefae0 (diff)
downloadmariadb-git-a2bafbabe2c1335bd411daf85dde8908e55dab62.tar.gz
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.
Diffstat (limited to 'sql/sql_window.cc')
-rw-r--r--sql/sql_window.cc105
1 files changed, 89 insertions, 16 deletions
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 4bb577a8f5e..92ff71fcf38 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -824,6 +824,17 @@ protected:
}
}
+ /* Clear all sum functions handled by this cursor. */
+ void clear_sum_functions()
+ {
+ List_iterator_fast<Item_sum> iter_sum_func(sum_functions);
+ Item_sum *sum_func;
+ while ((sum_func= iter_sum_func++))
+ {
+ sum_func->clear();
+ }
+ }
+
/* Sum functions that this cursor handles. */
List<Item_sum> sum_functions;
@@ -1847,17 +1858,6 @@ private:
Table_read_cursor cursor;
ha_rows curr_rownum;
- /* Clear all sum functions handled by this cursor. */
- void clear_sum_functions()
- {
- List_iterator_fast<Item_sum> iter_sum_func(sum_functions);
- Item_sum *sum_func;
- while ((sum_func= iter_sum_func++))
- {
- sum_func->clear();
- }
- }
-
/* Scan the rows between the top bound and bottom bound. Add all the values
between them, top bound row and bottom bound row inclusive. */
void compute_values_for_current_row()
@@ -1883,6 +1883,55 @@ private:
}
};
+/* A cursor that follows a target cursor. Each time a new row is added,
+ the window functions are cleared and only have the row at which the target
+ is point at added to them.
+*/
+class Frame_positional_cursor : public Frame_cursor
+{
+ public:
+ Frame_positional_cursor(const Frame_cursor &position_cursor) :
+ position_cursor(position_cursor) {}
+
+ void init(READ_RECORD *info)
+ {
+ cursor.init(info);
+ }
+
+ void pre_next_partition(ha_rows rownum)
+ {
+ clear_sum_functions();
+ }
+
+ void next_partition(ha_rows rownum)
+ {
+ cursor.move_to(position_cursor.get_curr_rownum());
+ add_value_to_items();
+ }
+
+ void pre_next_row()
+ {
+ }
+
+ void next_row()
+ {
+ if (position_cursor.is_outside_computation_bounds())
+ clear_sum_functions();
+
+ cursor.move_to(position_cursor.get_curr_rownum());
+ add_value_to_items();
+ }
+
+ ha_rows get_curr_rownum() const
+ {
+ return position_cursor.get_curr_rownum();
+ }
+
+private:
+ const Frame_cursor &position_cursor;
+ Table_read_cursor cursor;
+};
+
/*
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)
return NULL;
}
-void add_extra_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
- Item_window_func *window_func)
+static
+void add_special_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
+ Item_window_func *window_func)
{
Window_spec *spec= window_func->window_spec;
Item_sum *item_sum= window_func->window_func();
@@ -2010,6 +2060,19 @@ void add_extra_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
fc->add_sum_func(item_sum);
cursor_manager->add_cursor(fc);
break;
+ case Item_sum::FIRST_VALUE_FUNC:
+ fc= get_frame_cursor(thd, spec, true);
+ fc->set_no_action();
+ cursor_manager->add_cursor(fc);
+ fc= new Frame_positional_cursor(*fc);
+ fc->add_sum_func(item_sum);
+ cursor_manager->add_cursor(fc);
+ break;
+ case Item_sum::LAST_VALUE_FUNC:
+ fc= get_frame_cursor(thd, spec, false);
+ fc->add_sum_func(item_sum);
+ cursor_manager->add_cursor(fc);
+ break;
default:
fc= new Frame_unbounded_preceding(
thd, spec->partition_list, spec->order_list);
@@ -2032,6 +2095,8 @@ static bool is_computed_with_remove(Item_sum::Sumfunctype sum_func)
case Item_sum::RANK_FUNC:
case Item_sum::DENSE_RANK_FUNC:
case Item_sum::NTILE_FUNC:
+ case Item_sum::FIRST_VALUE_FUNC:
+ case Item_sum::LAST_VALUE_FUNC:
return false;
default:
return true;
@@ -2071,12 +2136,20 @@ void get_window_functions_required_cursors(
/*
If it is not a regular window function that follows frame specifications,
- specific cursors are required. ROW_NUM, RANK, NTILE and others follow
- such rules. Check is_frame_prohibited check for the full list.
+ and/or specific cursors are required. ROW_NUM, RANK, NTILE and others
+ follow such rules. Check is_frame_prohibited check for the full list.
+
+ TODO(cvicentiu) This approach is messy. Every time a function allows
+ computation in a certain way, we have to add an extra method to this
+ factory function. It is better to have window functions output
+ their own cursors, as needed. This way, the logic is bound
+ only to the implementation of said window function. Regular aggregate
+ functions can keep the default frame generating code, overwrite it or
+ add to it.
*/
if (item_win_func->is_frame_prohibited())
{
- add_extra_frame_cursors(thd, cursor_manager, item_win_func);
+ add_special_frame_cursors(thd, cursor_manager, item_win_func);
cursor_managers->push_back(cursor_manager);
continue;
}