Postgres SELECT DISTINCT Does Not Scale
PostgreSQL's SELECT DISTINCT always scans every matching row rather than leveraging indexes for unique values, causing performance to degrade linearly with table size.
summary is enough While the technical deep dive into query plans and the recursive CTE workaround is interesting, the limitation is a known PostgreSQL quirk well-documented in the community.
summary
PostgreSQL evaluates SELECT DISTINCT by performing a full index scan of all matching rows rather than jumping directly to unique values, causing performance to scale with table size rather than the number of unique entries. When testing a queue workload with few partitions but many rows, the authors found query latency grew linearly into seconds. To bypass this limitation, they implemented a recursive common table expression that mimics a loose index scan by iteratively fetching the minimum value. Commenters note that this behavior is a longstanding limitation without a native loose index scan operator.
key points
- SELECT DISTINCT in PostgreSQL always scans every row matching the predicate, ignoring the uniqueness of the target column in index evaluations.
- Query execution time scales linearly with the number of rows per partition rather than the number of distinct values returned.
- A recursive common table expression can force PostgreSQL to execute a loop over minimum values, bypassing full index scans for O(number of partitions) performance.
who should read it
Backend engineers and database administrators optimizing PostgreSQL query performance under high-volume queue workloads.
discussion skeptical
consensus
Commenters point out that PostgreSQL's lack of a native loose index scan for DISTINCT is a well-known, longstanding limitation documented on the official wiki. Many note that alternative approaches or proper data modeling should be evaluated first.
pushback
Some critics argue the issue is standard database behavior and question why it was presented as a novel discovery.
Loose index scan is made for this https://dev.mysql.com/doc/refman/8.0/en/group-by-optimizatio...
Postgres doesn't have it yet https://wiki.postgresql.org/wiki/Loose_indexscan
It links directly to the MySQL documentation and the PostgreSQL wiki page tracking the missing loose index scan feature.
Generated by an LLM from the article and thread. Check the sources before relying on it.