| From: | Ilia Evdokimov <ilya(dot)evdokimov(at)tantorlabs(dot)com> |
|---|---|
| To: | prankware <esavelievcode(at)gmail(dot)com>, Alexandre Felipe <o(dot)alexandre(dot)felipe(at)gmail(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org, Laurenz Albe <laurenz(dot)albe(at)cybertec(dot)at> |
| Subject: | Re: COALESCE patch |
| Date: | 2026-08-17 15:55:18 |
| Message-ID: | b86f780f-2897-41bc-ab95-74bf32784722@tantorlabs.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi everyone,
Thank you for working on it.
On 8/17/26 13:37, prankware wrote:
> v4 is attached. It passes the regression tests and gives the same
> estimates as before.
Testing v4 with a `COALESCE(...) <> const` clause, I found a case where
the estimate should be exactly recoverable but is not.
```
CREATE TABLE t (a INT);
INSERT INTO t SELECT (i % 10) FROM generate_series(1, 100000) i;
ANALYZE t;
EXPLAIN ANALYZE SELECT * FROM t1 WHERE a <> 5;
QUERY PLAN
----------------------------------------------------------------------------------------------------------
Seq Scan on t1 (cost=0.00..1693.00 rows=90057 width=4) (actual
time=0.382..9.287 rows=90000.00 loops=1)
Filter: (a <> 5)
Rows Removed by Filter: 10000
Buffers: shared read=443
Planning:
Buffers: shared hit=5
Planning Time: 0.150 ms
Execution Time: 11.502 ms
(8 rows)
EXPLAIN ANALYZE SELECT * FROM t1 WHERE COALESCE(a, 1) <> 5;
QUERY PLAN
----------------------------------------------------------------------------------------------------------
Seq Scan on t1 (cost=0.00..1693.00 rows=10260 width=4) (actual
time=0.049..6.034 rows=90000.00 loops=1)
Filter: (COALESCE(a, 1) <> 5)
Rows Removed by Filter: 10000
Buffers: shared hit=443
Planning Time: 0.145 ms
Execution Time: 7.977 ms
(6 rows)
```
Since a is never NULL here, COALESCE(a, 1) is identical to a on every
row, so the two queries' estimates should be the same - but they're off
by almost 9x. Moreover, I looked at MCV statistics
```
SELECT null_frac, most_common_vals, most_common_freqs FROM pg_stats
WHERE tablename = 't1';
null_frac | most_common_vals | most_common_freqs
-----------+-----------------------+---------------------------------------------------------------------------------------------------------
0 | {4,8,6,9,3,1,*5*,0,2,7} |
{0.10226667,0.10126667,0.10123333,0.1011,0.10073333,0.09946667,*0.09943333*,0.09903333,0.09826667,0.0972}
(1 row)
```
All 10 distinct values of a are captured as MCVs, so a <> 5 is
essentially exactly computable from these stats.
My guess is that the <> case ends up going through the COALESCE
decomposition without ever actually being turned into its `negator`
operator along the way.
--
Best regards,
Ilia Evdokimov,
Tantor Labs LLC,
https://tantorlabs.com/
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Álvaro Herrera | 2026-08-17 15:56:19 | Re: Tighten ACL check in repack_is_permitted_for_relation() |
| Previous Message | Tom Lane | 2026-08-17 15:41:36 | Re: Residual cleanups for tied objects in PL/Perl |