Hi remove_useless_join does not prove uniqueness if the unique index is partial, and therefore wont remove the join if no columns are referenced (see example in bottom).
I have been trying to look around the source code and from what I have identified the problem seems to be that "check_index_predicates(..)" happens after "remove_useless_join(..)", and therefore cannot see that the unique index is actually covered by the join condition. >From analyzejoins.c:612, rel_supports_distinctness(..) if (ind->unique && ind->immediate && (ind->indpred == NIL || ind->predOK)) return true; But the problem is ind->predOK is calculated in check_index_predicates(..) but this happens later so ind->predOK is always false when checked here. I have tried to add check_index_predicates(..) to rel_supports_distinctness(..) and this produces the expected plan, but I have no idea of the implication of doing check_index_predicates(..) earlier. This is my first time looking at the postgres source code, so I know attached "patch" is not the solution, but any pointers on where to go from here would be appreciated. Example: CREATE TABLE a ( id INTEGER PRIMARY KEY, sub_id INTEGER NOT NULL, deleted_at TIMESTAMP ); CREATE UNIQUE INDEX ON a (sub_id) WHERE (deleted_at IS NULL); ANALYZE a; EXPLAIN SELECT 1 FROM a AS a LEFT JOIN a AS b ON a.id = b.sub_id AND b.deleted_at IS NULL; Expected plan: QUERY PLAN ----------------------------------------------------- Seq Scan on a (cost=0.00..28.50 rows=1850 width=4) Actual plan: QUERY PLAN --------------------------------------------------------------------------------------- Hash Left Join (cost=14.76..48.13 rows=1850 width=4) Hash Cond: (a.id = b.sub_id) -> Seq Scan on a (cost=0.00..28.50 rows=1850 width=4) -> Hash (cost=14.65..14.65 rows=9 width=4) -> Bitmap Heap Scan on a b (cost=4.13..14.65 rows=9 width=4) Recheck Cond: (deleted_at IS NULL) -> Bitmap Index Scan on a_sub_id_idx (cost=0.00..4.13 rows=9 width=0) (7 rows) mvh Kim Carlsen Hiper A/S M: 71 99 42 00
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 1593dbec21..12da689983 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -596,6 +596,7 @@ rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel) return false; if (rel->rtekind == RTE_RELATION) { + check_index_predicates(root, rel); /* * For a plain relation, we only know how to prove uniqueness by * reference to unique indexes. Make sure there's at least one