Implement JOIN and subquery column elimination in dynamic select#284
Open
jongleb wants to merge 1 commit into
Open
Implement JOIN and subquery column elimination in dynamic select#284jongleb wants to merge 1 commit into
JOIN and subquery column elimination in dynamic select#284jongleb wants to merge 1 commit into
Conversation
88b5f44 to
bfb9529
Compare
jongleb
commented
Jun 12, 2026
Comment on lines
+753
to
+773
| let sub_exprs = function | ||
| | Value _ | Param _ | Inparam _ | Column _ | Of_values _ | SelectExpr _ -> [] | ||
| | Choices (_, l) -> List.filter_map snd l | ||
| | InChoice (_, _, e) -> [e] | ||
| | OptionActions { choice; _ } -> [choice] | ||
| | Fun { kind = Agg (With_order { order; _ }); parameters; _ } -> parameters @ List.map fst order | ||
| | Fun { parameters; _ } -> parameters | ||
| | InTupleList { value = { exprs; _ }; _ } -> exprs | ||
| | Case { case; branches; else_ } -> | ||
| option_list case | ||
| @ List.concat_map (fun (b : case_branch) -> [b.when_; b.then_]) branches | ||
| @ option_list else_ | ||
|
|
||
| let map_sub_exprs f = function | ||
| | Value _ | Param _ | Inparam _ | Column _ | Of_values _ | SelectExpr _ as e -> e | ||
| | Choices (n, l) -> Choices (n, List.map (fun (n, e) -> n, Option.map f e) l) | ||
| | InChoice (n, k, e) -> InChoice (n, k, f e) | ||
| | OptionActions ({ choice; _ } as o) -> OptionActions { o with choice = f choice } | ||
| | Fun ({ kind = Agg (With_order ({ order; _ } as wo)); parameters; _ } as fn) -> | ||
| Fun { fn with | ||
| kind = Agg (With_order { wo with order = List.map (fun (e, dir) -> f e, dir) order }); |
Collaborator
Author
There was a problem hiding this comment.
I was writing a tree walkthrough again and realized this is time to move it to a separate place.
Besides, adding a new expression forces us to go through every places adding a new match
https://gitlab.inria.fr/fpottier/visitors
and by the way it’s even easier to get all these maps and traverses by adding this ppx
jongleb
commented
Jun 12, 2026
Comment on lines
+604
to
+627
| let sub_vars = function | ||
| | Single _ | SingleIn _ | TupleList _ | DynamicSelectJoin _ -> [] | ||
| | ChoiceIn { vars; _ } -> vars | ||
| | OptionActionChoice (_, vars, _, _) -> vars | ||
| | SharedVarsGroup (vars, _) -> vars | ||
| | Choice (_, ctors) | DynamicSelect (_, ctors) -> List.concat_map ctor_vars ctors | ||
|
|
||
| let map_sub_vars f = | ||
| let map_ctor = function | ||
| | Simple (n, vars) -> Simple (n, Option.map f vars) | ||
| | Verbatim _ as c -> c | ||
| in | ||
| function | ||
| | Single _ | SingleIn _ | TupleList _ | DynamicSelectJoin _ as v -> v | ||
| | ChoiceIn t -> ChoiceIn { t with vars = f t.vars } | ||
| | OptionActionChoice (p, vars, pos, kind) -> OptionActionChoice (p, f vars, pos, kind) | ||
| | SharedVarsGroup (vars, id) -> SharedVarsGroup (f vars, id) | ||
| | Choice (p, ctors) -> Choice (p, List.map map_ctor ctors) | ||
| | DynamicSelect (p, ctors) -> DynamicSelect (p, List.map map_ctor ctors) | ||
|
|
||
| let var_pos = function | ||
| | Single (p, _) | SingleIn (p, _) -> fst p.id.pos | ||
| | Choice (id, _) | DynamicSelect (id, _) | TupleList (id, _) | ||
| | OptionActionChoice (id, _, _, _) -> fst id.pos |
Collaborator
Author
There was a problem hiding this comment.
#284 (comment)
taken out separately for the same reason
JOIN and subquery column elimination in dynamic select
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR introduces
LEFT JOINelimination for dynamic selects. It also works for subqueries as sources, it means that any columns not used in the final select will be removed automatically."For the user, there are two cases when it is convenient for the user to use this.
For example
Given this ddl
Before:
We could write three separate queries.Not only does the old approach force us to duplicate fields and parts of the query, but it also requires repeating the exact same
WHEREconditions every time.Since this PR
And then it could be used this way:
What kind of joins can be eliminated
Not every join can be eliminated. We can safely remove
LEFT JOINonly if right table is joined by unique key and its columns are not used anywhere else in query. In this case join doesn't affect row count or filtering. ExtraANDconditions on top of key match are fine, soON a.id = b.id AND b.type = 'x'is still droppable. But ifONclause doesn't guarantee unique match (for exampleON a.id = b.id OR b.type = 'x', inequality or just part of composite key), we must keep this join. Otherwise it can multiply rows and change final result.Subqueries
Before this PR the pick only affected the outer SELECT. The subquery always ran as written: all columns, all joins.
Before: pick name, pay for everything anyway:
The resulting query
After the subquery narrows together with the pick