Redundant outer DISTINCT adds Sort and Unique above INTERSECT

From: 陈列行 <2320415112(at)qq(dot)com>
To: pgsql-hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Redundant outer DISTINCT adds Sort and Unique above INTERSECT
Date: 2026-08-17 08:03:56
Message-ID: tencent_AB4A0A47D520BE8902655B29836BCEB05008@qq.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

## Description

This issue concerns an outer `DISTINCT` applied to an `INTERSECT` result.
Since non-`ALL` `INTERSECT` already returns duplicate-free rows, the outer
operation cannot change the result. PostgreSQL nevertheless performs a
second deduplication.

### Expected Behaviour

PostgreSQL should propagate the uniqueness guarantee from `INTERSECT` and
remove the outer `DISTINCT`. Both equivalent forms should use the same plan
and have comparable execution times.

### Actual Behaviour

The outer `DISTINCT` adds `Sort -&gt; Unique` above `HashSetOp Intersect`. With
two 500,000-row inputs and 250,000 result rows, five-run median execution
time increased from 176.081 ms to 191.225 ms, approximately 8.6%.

## How to repeat

```sql
DROP TABLE IF EXISTS intersect_distinct_lhs;
DROP TABLE IF EXISTS intersect_distinct_rhs;

CREATE TABLE intersect_distinct_lhs (v INTEGER NOT NULL);
CREATE TABLE intersect_distinct_rhs (v INTEGER NOT NULL);

INSERT INTO intersect_distinct_lhs
SELECT g FROM generate_series(1, 500000) AS g;

INSERT INTO intersect_distinct_rhs
SELECT g FROM generate_series(250001, 750000) AS g;

ANALYZE intersect_distinct_lhs;
ANALYZE intersect_distinct_rhs;

EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, TIMING OFF)
SELECT DISTINCT v
FROM (
&nbsp; &nbsp;SELECT v FROM intersect_distinct_lhs
&nbsp; &nbsp;INTERSECT
&nbsp; &nbsp;SELECT v FROM intersect_distinct_rhs
) AS set_result;

EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, TIMING OFF)
SELECT v
FROM (
&nbsp; &nbsp;SELECT v FROM intersect_distinct_lhs
&nbsp; &nbsp;INTERSECT
&nbsp; &nbsp;SELECT v FROM intersect_distinct_rhs
) AS set_result;
```

Both queries return the same 250,000 rows. The characteristic plans are:

```text
with DISTINCT: Unique -&gt; Sort -&gt; HashSetOp Intersect
without: &nbsp; &nbsp; &nbsp; HashSetOp Intersect
```

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2026-08-17 08:04:14 Switch opclass option functions to be STRICT (currently non-STRICT)
Previous Message 陈列行 2026-08-17 08:00:46 Duplicating an equivalent ANY predicate changes a semijoin into a slower per-row SubPlan