| From: | Zhang Ziming <toren(dot)zhang(at)outlook(dot)com> |
|---|---|
| To: | Chengpeng Yan <chengpeng_yan(at)outlook(dot)com>, "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Cc: | David Rowley <dgrowleyml(at)gmail(dot)com> |
| Subject: | RE: [PATCH] Restrict partial unique index estimates to base quals |
| Date: | 2026-10-31 06:56:46 |
| Message-ID: | TY3P301MB06581CE533F14947FBFB8A6BEF6C2@TY3P301MB0658.JPNP301.PROD.OUTLOOK.COM |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi, Chengpeng
The predOKBase distinction makes sense to me, but I'm wondering whether
using it unconditionally in examine_variable() changes more than
intended:
```diff
if (index->unique &&
index->nkeycolumns == 1 &&
pos == 0 &&
- (index->indpred == NIL || index->predOK))
+ (index->indpred == NIL || index->predOKBase))
vardata->isunique = true;
```
Since eqjoinsel() also uses examine_variable(), this change affects join
estimates even when the join conditions imply the index predicate.
For example:
```sql
CREATE TABLE p (id int, code int);
CREATE TABLE c (parent_id int, code int);
CREATE UNIQUE INDEX c_expr ON c ((code + 0))
WHERE parent_id IS NOT NULL;
INSERT INTO p VALUES (1, 42);
INSERT INTO c SELECT 1, g FROM generate_series(1, 10000) g;
INSERT INTO c SELECT NULL, 42 FROM generate_series(1, 10000);
ANALYZE p, c;
SET enable_nestloop = off;
SET enable_mergejoin = off;
EXPLAIN (ANALYZE, TIMING OFF, SUMMARY OFF, BUFFERS OFF)
SELECT * FROM p JOIN c
ON c.parent_id = p.id AND c.code + 0 = p.code;
```
I tested on PostgreSQL 20devel, with and without v1. The EXPLAIN difference
is:
```diff
-Hash Join (cost=1.02..465.03 rows=1 width=16) (actual rows=1.00 loops=1)
+Hash Join (cost=1.02..465.52 rows=50 width=16) (actual rows=1.00 loops=1)
Hash Cond: ((c.parent_id = p.id) AND ((c.code + 0) = p.code))
-> Seq Scan on c (cost=0.00..289.00 rows=20000 width=8) (actual rows=20000.00 loops=1)
-> Hash (cost=1.01..1.01 rows=1 width=8) (actual rows=1.00 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Seq Scan on p (cost=0.00..1.01 rows=1 width=8) (actual rows=1.00 loops=1)
```
Here the join conditions imply parent_id IS NOT NULL, so each p row can
match at most one c row. With v1, predOKBase is false and
examine_variable() no longer supplies that uniqueness information to
eqjoinsel().
Losing this information may also affect the join order and the cost
estimates of subsequent joins, so the impact could extend beyond the row
estimate shown here.
Could we distinguish base-relation restriction estimates from join
estimates here, so that the former use the base-only proof while the
latter can still benefit from uniqueness when the relevant join
conditions imply the index predicate?
Best regards,
Ziming Zhang
| From | Date | Subject | |
|---|---|---|---|
| Previous Message | Roman Khapov | 2026-10-31 06:54:32 | Print latency percentiles in pgbench |