mirror of
https://github.com/postgres/postgres.git
synced 2025-05-29 00:03:09 -04:00
Allow incremental sorts for windowing functions
This expands on the work done in d2d8a229b and allows incremental sort to be considered during create_window_paths(). Author: David Rowley Reviewed-by: Daniel Gustafsson, Tomas Vondra Discussion: https://postgr.es/m/CAApHDvoOHobiA2x13NtWnWLcTXYj9ddpCkv9PnAJQBMegYf_xw%40mail.gmail.com
This commit is contained in:
parent
fe4f36bcde
commit
62e221e1c0
@ -4582,14 +4582,17 @@ create_window_paths(PlannerInfo *root,
|
|||||||
/*
|
/*
|
||||||
* Consider computing window functions starting from the existing
|
* Consider computing window functions starting from the existing
|
||||||
* cheapest-total path (which will likely require a sort) as well as any
|
* cheapest-total path (which will likely require a sort) as well as any
|
||||||
* existing paths that satisfy root->window_pathkeys (which won't).
|
* existing paths that satisfy or partially satisfy root->window_pathkeys.
|
||||||
*/
|
*/
|
||||||
foreach(lc, input_rel->pathlist)
|
foreach(lc, input_rel->pathlist)
|
||||||
{
|
{
|
||||||
Path *path = (Path *) lfirst(lc);
|
Path *path = (Path *) lfirst(lc);
|
||||||
|
int presorted_keys;
|
||||||
|
|
||||||
if (path == input_rel->cheapest_total_path ||
|
if (path == input_rel->cheapest_total_path ||
|
||||||
pathkeys_contained_in(root->window_pathkeys, path->pathkeys))
|
pathkeys_count_contained_in(root->window_pathkeys, path->pathkeys,
|
||||||
|
&presorted_keys) ||
|
||||||
|
presorted_keys > 0)
|
||||||
create_one_window_path(root,
|
create_one_window_path(root,
|
||||||
window_rel,
|
window_rel,
|
||||||
path,
|
path,
|
||||||
@ -4664,18 +4667,42 @@ create_one_window_path(PlannerInfo *root,
|
|||||||
{
|
{
|
||||||
WindowClause *wc = lfirst_node(WindowClause, l);
|
WindowClause *wc = lfirst_node(WindowClause, l);
|
||||||
List *window_pathkeys;
|
List *window_pathkeys;
|
||||||
|
int presorted_keys;
|
||||||
|
bool is_sorted;
|
||||||
|
|
||||||
window_pathkeys = make_pathkeys_for_window(root,
|
window_pathkeys = make_pathkeys_for_window(root,
|
||||||
wc,
|
wc,
|
||||||
root->processed_tlist);
|
root->processed_tlist);
|
||||||
|
|
||||||
|
is_sorted = pathkeys_count_contained_in(window_pathkeys,
|
||||||
|
path->pathkeys,
|
||||||
|
&presorted_keys);
|
||||||
|
|
||||||
/* Sort if necessary */
|
/* Sort if necessary */
|
||||||
if (!pathkeys_contained_in(window_pathkeys, path->pathkeys))
|
if (!is_sorted)
|
||||||
{
|
{
|
||||||
path = (Path *) create_sort_path(root, window_rel,
|
/*
|
||||||
path,
|
* No presorted keys or incremental sort disabled, just perform a
|
||||||
window_pathkeys,
|
* complete sort.
|
||||||
-1.0);
|
*/
|
||||||
|
if (presorted_keys == 0 || !enable_incremental_sort)
|
||||||
|
path = (Path *) create_sort_path(root, window_rel,
|
||||||
|
path,
|
||||||
|
window_pathkeys,
|
||||||
|
-1.0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Since we have presorted keys and incremental sort is
|
||||||
|
* enabled, just use incremental sort.
|
||||||
|
*/
|
||||||
|
path = (Path *) create_incremental_sort_path(root,
|
||||||
|
window_rel,
|
||||||
|
path,
|
||||||
|
window_pathkeys,
|
||||||
|
presorted_keys,
|
||||||
|
-1.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lnext(activeWindows, l))
|
if (lnext(activeWindows, l))
|
||||||
|
@ -3200,6 +3200,50 @@ FROM empsalary;
|
|||||||
-> Seq Scan on empsalary
|
-> Seq Scan on empsalary
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- Test incremental sorting
|
||||||
|
EXPLAIN (COSTS OFF)
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT depname,
|
||||||
|
empno,
|
||||||
|
salary,
|
||||||
|
enroll_date,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date) AS first_emp,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date DESC) AS last_emp
|
||||||
|
FROM empsalary) emp
|
||||||
|
WHERE first_emp = 1 OR last_emp = 1;
|
||||||
|
QUERY PLAN
|
||||||
|
-----------------------------------------------------------------------------------
|
||||||
|
Subquery Scan on emp
|
||||||
|
Filter: ((emp.first_emp = 1) OR (emp.last_emp = 1))
|
||||||
|
-> WindowAgg
|
||||||
|
-> Incremental Sort
|
||||||
|
Sort Key: empsalary.depname, empsalary.enroll_date
|
||||||
|
Presorted Key: empsalary.depname
|
||||||
|
-> WindowAgg
|
||||||
|
-> Sort
|
||||||
|
Sort Key: empsalary.depname, empsalary.enroll_date DESC
|
||||||
|
-> Seq Scan on empsalary
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT depname,
|
||||||
|
empno,
|
||||||
|
salary,
|
||||||
|
enroll_date,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date) AS first_emp,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date DESC) AS last_emp
|
||||||
|
FROM empsalary) emp
|
||||||
|
WHERE first_emp = 1 OR last_emp = 1;
|
||||||
|
depname | empno | salary | enroll_date | first_emp | last_emp
|
||||||
|
-----------+-------+--------+-------------+-----------+----------
|
||||||
|
develop | 8 | 6000 | 10-01-2006 | 1 | 5
|
||||||
|
develop | 7 | 4200 | 01-01-2008 | 5 | 1
|
||||||
|
personnel | 2 | 3900 | 12-23-2006 | 1 | 2
|
||||||
|
personnel | 5 | 3500 | 12-10-2007 | 2 | 1
|
||||||
|
sales | 1 | 5000 | 10-01-2006 | 1 | 3
|
||||||
|
sales | 4 | 4800 | 08-08-2007 | 3 | 1
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
-- cleanup
|
-- cleanup
|
||||||
DROP TABLE empsalary;
|
DROP TABLE empsalary;
|
||||||
-- test user-defined window function with named args and default args
|
-- test user-defined window function with named args and default args
|
||||||
|
@ -936,6 +936,28 @@ SELECT
|
|||||||
lag(1) OVER (PARTITION BY depname ORDER BY salary,enroll_date,empno)
|
lag(1) OVER (PARTITION BY depname ORDER BY salary,enroll_date,empno)
|
||||||
FROM empsalary;
|
FROM empsalary;
|
||||||
|
|
||||||
|
-- Test incremental sorting
|
||||||
|
EXPLAIN (COSTS OFF)
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT depname,
|
||||||
|
empno,
|
||||||
|
salary,
|
||||||
|
enroll_date,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date) AS first_emp,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date DESC) AS last_emp
|
||||||
|
FROM empsalary) emp
|
||||||
|
WHERE first_emp = 1 OR last_emp = 1;
|
||||||
|
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT depname,
|
||||||
|
empno,
|
||||||
|
salary,
|
||||||
|
enroll_date,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date) AS first_emp,
|
||||||
|
row_number() OVER (PARTITION BY depname ORDER BY enroll_date DESC) AS last_emp
|
||||||
|
FROM empsalary) emp
|
||||||
|
WHERE first_emp = 1 OR last_emp = 1;
|
||||||
|
|
||||||
-- cleanup
|
-- cleanup
|
||||||
DROP TABLE empsalary;
|
DROP TABLE empsalary;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user