Fix costing bug in MergeAppend

When building a MergeAppendPath which has child paths that are not
sorted correctly for the MergeAppend's sort order, we apply the cost of
sorting those paths to the MergeAppendPath costs.

Here we fix a bug where the number of tuples specified that needed to be
sorted was effectively pg_class.reltuples rather than the number of
expected row in the subpath.  This effectively penalizes MergeAppend
plans any time any filter is present on the MergeAppend subpath as the
sort cost added is to sort all tuples in the table rather than just the
ones expected the path to return.

This did not affect UNION ALL type queries as the RelOptInfo tuples is
set from the subquery's path rows.  It does affect MergeAppends uses for
inheritance and partitioned tables.

This is a long-standing bug introduced when MergeAppend was first added
in 11cad29c9.  No backpatch as this could result in plan changes.

Author: Alexander Kuzmenkov
Reviewed-by: Ashutosh Bapat, Aleksander Alekseev, David Rowley
Discussion: https://postgr.es/m/CALzhyqyhoXQDR-Usd_0HeWk%3DuqNLzoVeT8KhRoo%3DpV_KzgO3QQ%40mail.gmail.com
This commit is contained in:
David Rowley 2024-02-01 09:48:26 +13:00
parent 9589b038d3
commit 9d1a5354f5
3 changed files with 37 additions and 1 deletions

View File

@ -1470,7 +1470,7 @@ create_merge_append_path(PlannerInfo *root,
root,
pathkeys,
subpath->total_cost,
subpath->parent->tuples,
subpath->rows,
subpath->pathtarget->width,
0.0,
work_mem,

View File

@ -1714,6 +1714,29 @@ order by t1.b limit 10;
(14 rows)
reset enable_nestloop;
drop table matest0 cascade;
NOTICE: drop cascades to table matest1
-- Test a MergeAppend plan where one child requires a sort
create table matest0(a int primary key);
create table matest1() inherits (matest0);
insert into matest0 select generate_series(1, 400);
insert into matest1 select generate_series(1, 200);
analyze matest0;
analyze matest1;
explain (costs off)
select * from matest0 where a < 100 order by a;
QUERY PLAN
---------------------------------------------------------------
Merge Append
Sort Key: matest0.a
-> Index Only Scan using matest0_pkey on matest0 matest0_1
Index Cond: (a < 100)
-> Sort
Sort Key: matest0_2.a
-> Seq Scan on matest1 matest0_2
Filter: (a < 100)
(8 rows)
drop table matest0 cascade;
NOTICE: drop cascades to table matest1
--

View File

@ -624,6 +624,19 @@ reset enable_nestloop;
drop table matest0 cascade;
-- Test a MergeAppend plan where one child requires a sort
create table matest0(a int primary key);
create table matest1() inherits (matest0);
insert into matest0 select generate_series(1, 400);
insert into matest1 select generate_series(1, 200);
analyze matest0;
analyze matest1;
explain (costs off)
select * from matest0 where a < 100 order by a;
drop table matest0 cascade;
--
-- Test merge-append for UNION ALL append relations
--