| From: | ZizhuanLiu X-MAN <44973863(at)qq(dot)com> |
|---|---|
| To: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> |
| Cc: | pgsql-hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: Fix var_eq_const: sum selectivity of all matching MCV entries instead of stopping at first match |
| Date: | 2026-08-04 11:40:07 |
| Message-ID: | tencent_1A35AAC193B491D27E4C047FDB59D650630A@qq.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Original
>From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
>Date: 2026-07-30 21:39
>To: ZizhuanLiu X-MAN <44973863(at)qq(dot)com>
>Cc: pgsql-hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
>Subject: Re: Fix var_eq_const: sum selectivity of all matching MCV entries instead of stopping at first match
>"=?utf-8?B?Wml6aHVhbkxpdSBYLU1BTg==?=" <44973863(at)qq(dot)com> writes:
>> While reviewing CF6397(https://commitfest.postgresql.org/patch/6397/), I noticed that
>> the function `var_eq_const()` located at `backend/utils/adt/selfuncs.c` consumes statistical
>> data from the `most_common_vals` and `most_common_freqs` columns in the system
>> catalog `pg_catalog.pg_stats`. Currently, the function terminates iteration immediately
>> after finding the first matching entry and adopts the selectivity of this single matched value.
>
>> I believe this estimation logic is inaccurate. Instead, we should traverse all entries in
>> `most_common_vals`, check for matches against each entry, and sum up the selectivities
>> of all matching items.
>
>That would double the function's runtime on average, without changing
>the results at all in most cases (it could only be different if the
>given operator has different semantics from the equality operator used
>while building the statistics list). I think you need a far stronger
>argument for changing the existing tradeoff than "I believe".
>
>regards, tom lane
Hi, tom, hackers
Thanks for the review and important feedback.
From an algorithm perspective, the average complexity shifts from
N/2 to a fixed O(N) full scan, adding performance overhead. I had
not accounted for this downside earlier.
After examining pg_catalog.pg_collation, I found that all preloaded
collations have collisdeterministic = true.
This applies to all provider types: d (default), b (builtin), c (libc), and i (icu).
Below is the statistic from my test environment (ICU enabled):
```sql
select collprovider,collisdeterministic,count(*) from pg_catalog.pg_collation group by 1,2;
collprovider | collisdeterministic | count
--------------+---------------------+-------
c | t | 3
b | t | 3
i | t | 853
d | t | 1
i | f | 1
The single row with collisdeterministic = false is the custom collation I created:
```sql
CREATE COLLATION case_insensitive (provider = icu, locale = 'und-u-ks-level2', deterministic = false);
As required by PostgreSQL collation rules, deterministic = false
must be explicitly specified to create a non-deterministic collation.
Only when collisdeterministic = false can a comparison match
multiple binary-distinct strings.
For example:
'a' COLLATE case_insensitive can match both 'A' and 'a' stored in MCV
entries collected under a deterministic collation.
Similarly, plain values 'A' / 'a' can match MCV entries which defined
by COLLATE case_insensitive.
By comparing the collation OID of the attribute and the expression, together with each collation’s collisdeterministic property, I have outlined the following decision table:
attribute-collation | expr-collation | | |
coll-oid | deterministic? | coll-oid | deterministic? | oid eq? | mcv-scan-strategy |
---------+--------------+---------+----------------+--------+--------------------
x | dem | x | dem | == | first/fast |
x | dem | y | dem | <> | first/fast |
x | non | x | non | == | first/fast |
x | non | y | non | <> | first/fast |
x | non | y | dem | <> | all/low |
x | dem | y | non | <> | all/low |
-------------------------------------------------------------------------------------
Where:
dem = deterministic
non = non-deterministic
The MCV list holds up to 100 entries by default; this limit can be adjusted via
ALTER TABLE ... ALTER COLUMN ... SET STATISTICS (range 0 to 10000).
Accurate row estimates are critical for planner decisions such as choosing
the driving table in a Nested Loop Join. Poor estimates can lead to drastically
incorrect cost calculations and bad plans.
This proposed strategy preserves the existing fast first-match logic for the vast majority of workloads, maintaining
current performance characteristics.
Meanwhile it enables accurate selectivity estimation for the
special mixed-collation scenario described above.
This is the approach I have in mind. Please let me know
if there are flaws or missing considerations.
If the overall direction looks reasonable, I will move on to
work out the concrete code adaptations.
regards,
--
ZizhuanLiu (X-MAN)
44973863(at)qq(dot)com
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Michael Paquier | 2026-08-04 11:41:35 | Re: Streamify more code paths |
| Previous Message | Zhijie Hou (Fujitsu) | 2026-08-04 11:33:37 | RE: [PATCH] Release replication slot on error in SQL-callable slot functions |