diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 4a330192f2..9151d53b62 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1282,6 +1282,43 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, /* If appropriate, consider parallel append */ pa_subpaths_valid = enable_parallel_append && rel->consider_parallel; + /* + * When the partitioned table is partitioned in a way that naturally + * guarantees some ordering, we'll add the pathkeys for that order to + * all_child_pathkeys. In generate_orderedappend_paths this may allow + * sorts to be pushed below an Append in more cases. + */ + if (rel->part_scheme != NULL && IS_SIMPLE_REL(rel) && + partitions_are_ordered(rel->boundinfo, rel->live_parts)) + { + List *partition_pathkeys; + bool partial; + + partition_pathkeys = build_partition_pathkeys(root, rel, + ForwardScanDirection, + &partial); + + partition_pathkeys = truncate_useless_pathkeys(root, rel, + partition_pathkeys); + + /* we need not pay attention to partial matches */ + if (partition_pathkeys != NULL) + all_child_pathkeys = lappend(all_child_pathkeys, + partition_pathkeys); + + /* as above but for DESC ordering */ + partition_pathkeys = build_partition_pathkeys(root, rel, + BackwardScanDirection, + &partial); + + partition_pathkeys = truncate_useless_pathkeys(root, rel, + partition_pathkeys); + + if (partition_pathkeys != NULL) + all_child_pathkeys = lappend(all_child_pathkeys, + partition_pathkeys); + } + /* * For every non-dummy child, remember the cheapest path. Also, identify * all pathkeys (orderings) and parameterizations (required_outer sets) diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 2d49e765de..c75d0ab465 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -2423,7 +2423,7 @@ drop table bool_rp; create table range_parted (a int, b int, c int) partition by range(a, b); create table range_parted1 partition of range_parted for values from (0,0) to (10,10); create table range_parted2 partition of range_parted for values from (10,10) to (20,20); -create index on range_parted (a,b,c); +create index range_parted_a_b_c_idx on range_parted (a,b,c); explain (costs off) select * from range_parted order by a,b,c; QUERY PLAN ------------------------------------------------------------------------------------- @@ -2440,6 +2440,58 @@ explain (costs off) select * from range_parted order by a desc,b desc,c desc; -> Index Only Scan Backward using range_parted1_a_b_c_idx on range_parted1 range_parted_1 (3 rows) +drop index range_parted_a_b_c_idx; +-- Ensure we make use of an Append scan even when no index exists to provide +-- presorted input. We expect we can push a Sort below the Append. +explain (costs off) select * from range_parted order by a; + QUERY PLAN +------------------------------------------------------ + Append + -> Sort + Sort Key: range_parted_1.a + -> Seq Scan on range_parted1 range_parted_1 + -> Sort + Sort Key: range_parted_2.a + -> Seq Scan on range_parted2 range_parted_2 +(7 rows) + +explain (costs off) select * from range_parted order by a desc; + QUERY PLAN +------------------------------------------------------ + Append + -> Sort + Sort Key: range_parted_2.a DESC + -> Seq Scan on range_parted2 range_parted_2 + -> Sort + Sort Key: range_parted_1.a DESC + -> Seq Scan on range_parted1 range_parted_1 +(7 rows) + +-- As above but with a more strict ordering requirement +explain (costs off) select * from range_parted order by a,b; + QUERY PLAN +------------------------------------------------------ + Append + -> Sort + Sort Key: range_parted_1.a, range_parted_1.b + -> Seq Scan on range_parted1 range_parted_1 + -> Sort + Sort Key: range_parted_2.a, range_parted_2.b + -> Seq Scan on range_parted2 range_parted_2 +(7 rows) + +explain (costs off) select * from range_parted order by a desc,b desc; + QUERY PLAN +---------------------------------------------------------------- + Append + -> Sort + Sort Key: range_parted_2.a DESC, range_parted_2.b DESC + -> Seq Scan on range_parted2 range_parted_2 + -> Sort + Sort Key: range_parted_1.a DESC, range_parted_1.b DESC + -> Seq Scan on range_parted1 range_parted_1 +(7 rows) + drop table range_parted; -- Check that we allow access to a child table's statistics when the user -- has permissions only for the parent table. diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 195aedb5ff..c2d26dc860 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -866,11 +866,22 @@ drop table bool_rp; create table range_parted (a int, b int, c int) partition by range(a, b); create table range_parted1 partition of range_parted for values from (0,0) to (10,10); create table range_parted2 partition of range_parted for values from (10,10) to (20,20); -create index on range_parted (a,b,c); +create index range_parted_a_b_c_idx on range_parted (a,b,c); explain (costs off) select * from range_parted order by a,b,c; explain (costs off) select * from range_parted order by a desc,b desc,c desc; +drop index range_parted_a_b_c_idx; + +-- Ensure we make use of an Append scan even when no index exists to provide +-- presorted input. We expect we can push a Sort below the Append. +explain (costs off) select * from range_parted order by a; +explain (costs off) select * from range_parted order by a desc; + +-- As above but with a more strict ordering requirement +explain (costs off) select * from range_parted order by a,b; +explain (costs off) select * from range_parted order by a desc,b desc; + drop table range_parted; -- Check that we allow access to a child table's statistics when the user