| From: | Etsuro Fujita <etsuro(dot)fujita(at)gmail(dot)com> |
|---|---|
| To: | Bharath Rupireddy <bharath(dot)rupireddyforpostgres(at)gmail(dot)com> |
| Cc: | PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Corey Huinker <corey(dot)huinker(at)gmail(dot)com> |
| Subject: | Re: Further cleanup related to statistics import support in postgres_fdw |
| Date: | 2026-08-30 11:50:55 |
| Message-ID: | CAPmGK173b2Xvyoeq=Y7L09H+ajgMgxC2fYe=7CCunZz8tGTfFA@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
I added Corey in CC, who is the author of this feature. I should have
done this from the beginning. Corey, sorry for that.
I continued to self-re-review the commit, and I found issues (by hand)
that can lead to plan changes depending on the ANALYZE method.
create table pt (a int, b int) partition by list (a);
create table p1 partition of pt for values in (1);
create table p2 partition of pt for values in (2);
insert into pt select 1, i from generate_series(1, 1000) i;
insert into pt select 2, i from generate_series(1, 1000) i;
create foreign table fpt (a int, b int) server loopback options
(table_name 'pt');
analyze pt;
analyze fpt;
select relpages, reltuples from pg_class where relname = 'fpt';
relpages | reltuples
----------+-----------
0 | 2000
(1 row)
alter foreign table fpt options (add import_stats 'true');
analyze fpt;
select relpages, reltuples from pg_class where relname = 'fpt';
relpages | reltuples
----------+-----------
-1 | 2000
(1 row)
The normal method produces relpages = 0, whereas the import method
produces relpages = -1. The reason is that to produce it, the former
uses pg_relation_size(), which returns 0 for a partition root, but the
latter imports relpages as-is from the remote pg_class. As relpages
is used for costing foreign paths, this divergence can lead to the
plan changes.
Another example is:
create table parent (a int, b int);
create table child (a int, b int) inherits (parent);
insert into parent select 1, i from generate_series(1, 1000) i;
insert into child select 2, i from generate_series(1, 1000) i;
create foreign table fparent (a int, b int) server loopback options
(table_name 'parent');
analyze parent;
analyze fparent;
select relpages, reltuples from pg_class where relname = 'fparent';
relpages | reltuples
----------+-----------
5 | 2000
(1 row)
alter foreign table fparent options (add import_stats 'true');
analyze fparent;
select relpages, reltuples from pg_class where relname = 'fparent';
relpages | reltuples
----------+-----------
5 | 1000
(1 row)
Both methods produce the same relpages, but not for reltuples. The
reason is that in the latter, the reltuples estimate, which is
imported as-is from the remote pg_class as in the case of relpages, is
just the one for the inheritance parent, not for the inheritance set.
reltuples is also used for costing foreign paths, so this can also
lead to the plan changes.
To fix, for the partitioning case, I modified postgres_fdw to import
relpages = 0, to match the normal case. For the inheritance case, we
could calculate the reltuples estimate for the inheritance set by
fetching those for child tables as well, but 1) changes for that isn't
small, and 2) IMO table inheritance hasn't been used that much these
days, so I just disabled the import method in that case.
Attached is a patch for that.
(The normal method's relpages estimation in these cases is also
broken, as pg_relation_size() just returns the size of the parent
table, not the total size of the partitioned/inherited table. But
that is another issue, so I'd like to leave it for future work.)
Best regards,
Etsuro Fujita
| Attachment | Content-Type | Size |
|---|---|---|
| yet-further-cleanup.patch | application/octet-stream | 9.6 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Vaijayanti Bharadwaj | 2026-08-30 13:14:53 | SSI: A patch for a Serializability violation |
| Previous Message | Alexandre Felipe | 2026-08-30 10:35:14 | [PATCH] handling transitions in timestamptz_trunc_* |