Re: Removing unneeded self joins
Ronan Dunklau <ronan.dunklau@aiven.io>
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Remove GUC_NOT_IN_SAMPLE from enable_self_join_elimination
- 717d0e8dd945 18.0 landed
-
Put enable_self_join_elimination into postgresql.conf.sample
- c2d329260cd8 18.0 landed
-
Get rid of ojrelid local variable in remove_rel_from_query()
- e167191dc146 18.0 landed
-
Implement Self-Join Elimination
- fc069a3a6319 18.0 cited
-
Revert: Remove useless self-joins
- d1d286d83c0e 17.0 landed
-
Replace lateral references to removed rels in subqueries
- 466979ef031a 17.0 landed
-
Replace relids in lateral subquery parse tree during SJE
- 489072ab7a9e 17.0 landed
-
Forbid SJE with result relation
- 8c441c082797 17.0 landed
-
Fix misuse of RelOptInfo.unique_for_rels cache by SJE
- 30b4955a4668 17.0 landed
-
Replace the relid in some missing fields during SJE
- a7928a57b9f0 17.0 landed
-
Revert 56-bit relfilenode change and follow-up commits.
- a448e49bcbe4 16.0 cited
-
Stabilize timetz test across DST transitions.
- 4a071afbd056 14.0 cited
-
Speed up finding EquivalenceClasses for a given set of rels
- 3373c7155350 13.0 cited
-
Fix mark-and-restore-skipping test case to not be a self-join.
- 24d08f3c0a1f 12.0 landed
Le jeudi 30 juin 2022, 16:11:51 CEST Andrey Lepikhov a écrit :
> On 19/5/2022 16:47, Ronan Dunklau wrote:
> > I'll take a look at that one.
>
> New version of the patch, rebased on current master:
> 1. pgindent over the patch have passed.
> 2. number of changed files is reduced.
> 3. Some documentation and comments is added.
Hello Andrey,
Thanks for the updates.
The general approach seems sensible to me, so I'm going to focus on some details.
In a very recent thread [1], Tom Lane is proposing to add infrastructure to make Var aware of their nullability by outer joins. I wonder if that would help with avoiding the need for adding is not null clauses when the column is known not null ?
If we have a precedent for adding a BitmapSet to the Var itself, maybe the whole discussion regarding keeping track of nullability can be extended to the original column nullability ?
Also, I saw it was mentioned earlier in the thread but how difficult would it be to process the transformed quals through the EquivalenceClass machinery and the qual simplification ?
For example, if the target audience of this patch is ORM, or inlined views, it wouldn't surprise me to see queries of this kind in the wild, which could be avoided altogether:
postgres=# explain (costs off) select * from sj s1 join sj s2 on s1.a = s2.a where s1.b = 2 and s2.b =3;
QUERY PLAN
-----------------------------------------------------
Seq Scan on sj s2
Filter: ((a IS NOT NULL) AND (b = 3) AND (b = 2))
(2 lignes)
+ for (counter = 0; counter < list_length(*sources);)
+ {
+ ListCell *cell = list_nth_cell(*sources, counter);
+ RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(cell));
+ int counter1;
+
....
+ ec->ec_members = list_delete_cell(ec->ec_members, cell);
Why don't you use foreach() and foreach_delete_current macros for iterating and removing items in the lists, both in update_ec_members and update_ec_sources ?
+ if ((bms_is_member(k, info->syn_lefthand) ^
+ bms_is_member(r, info->syn_lefthand)) ||
+ (bms_is_member(k, info->syn_righthand) ^
+ bms_is_member(r, info->syn_righthand)))
I think this is more compact and easier to follow than the previous version, but I'm not sure how common it is in postgres source code to use that kind of construction ?
Some review about the comments:
I see you keep using the terms "the keeping relation" and "the removing relation" in reference to the relation that is kept and the one that is removed.
Aside from the grammar (the kept relation or the removed relation), maybe it would make it clearer to call them something else. In other parts of the code, you used "the remaining relation / the removed relation" which makes sense.
/*
* Remove the target relid from the planner's data structures, having
- * determined that there is no need to include it in the query.
+ * determined that there is no need to include it in the query. Or replace
+ * with another relid.
+ * To reusability, this routine can work in two modes: delete relid from a plan
+ * or replace it. It is used in replace mode in a self-join removing process.
This could be rephrased: ", optionally replacing it with another relid. The latter is used by the self-join removing process."
[1] https://www.postgresql.org/message-id/flat/830269.1656693747%40sss.pgh.pa.us
--
Ronan Dunklau