Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 77387f0

Browse files
committed
Suppress creation of backwardly-indexed paths for LATERAL join clauses.
Given a query such as SELECT * FROM foo JOIN LATERAL (SELECT foo.var1) ss(x) ON ss.x = foo.var2 the existence of the join clause "ss.x = foo.var2" encourages indxpath.c to build a parameterized path for foo using any index available for foo.var2. This is completely useless activity, though, since foo has got to be on the outside not the inside of any nestloop join with ss. It's reasonably inexpensive to add tests that prevent creation of such paths, so let's do that.
1 parent 35738b5 commit 77387f0

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

src/backend/optimizer/path/equivclass.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -1969,11 +1969,15 @@ mutate_eclass_expressions(PlannerInfo *root,
19691969
* is no value in using more than one. (But it *is* worthwhile to create
19701970
* a separate parameterized path for each one, since that leads to different
19711971
* join orders.)
1972+
*
1973+
* The caller can pass a Relids set of rels we aren't interested in joining
1974+
* to, so as to save the work of creating useless clauses.
19721975
*/
19731976
List *
19741977
generate_implied_equalities_for_indexcol(PlannerInfo *root,
19751978
IndexOptInfo *index,
1976-
int indexcol)
1979+
int indexcol,
1980+
Relids prohibited_rels)
19771981
{
19781982
List *result = NIL;
19791983
RelOptInfo *rel = index->rel;
@@ -2050,6 +2054,10 @@ generate_implied_equalities_for_indexcol(PlannerInfo *root,
20502054
bms_overlap(other_em->em_relids, rel->relids))
20512055
continue;
20522056

2057+
/* Forget it if caller doesn't want joins to this rel */
2058+
if (bms_overlap(other_em->em_relids, prohibited_rels))
2059+
continue;
2060+
20532061
/*
20542062
* Also, if this is a child rel, avoid generating a useless join
20552063
* to its parent rel.

src/backend/optimizer/path/indxpath.c

+35-6
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,12 @@ static void match_restriction_clauses_to_index(RelOptInfo *rel,
121121
IndexClauseSet *clauseset);
122122
static void match_join_clauses_to_index(PlannerInfo *root,
123123
RelOptInfo *rel, IndexOptInfo *index,
124+
Relids lateral_referencers,
124125
IndexClauseSet *clauseset,
125126
List **joinorclauses);
126127
static void match_eclass_clauses_to_index(PlannerInfo *root,
127128
IndexOptInfo *index,
129+
Relids lateral_referencers,
128130
IndexClauseSet *clauseset);
129131
static void match_clauses_to_index(IndexOptInfo *index,
130132
List *clauses,
@@ -211,22 +213,40 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
211213
List *bitindexpaths;
212214
List *bitjoinpaths;
213215
List *joinorclauses;
216+
Relids lateral_referencers;
214217
IndexClauseSet rclauseset;
215218
IndexClauseSet jclauseset;
216219
IndexClauseSet eclauseset;
217-
ListCell *ilist;
220+
ListCell *lc;
218221

219222
/* Skip the whole mess if no indexes */
220223
if (rel->indexlist == NIL)
221224
return;
222225

226+
/*
227+
* If there are any rels that have LATERAL references to this one, we
228+
* cannot use join quals referencing them as index quals for this one,
229+
* since such rels would have to be on the inside not the outside of a
230+
* nestloop join relative to this one. Create a Relids set listing all
231+
* such rels, for use in checks of potential join clauses.
232+
*/
233+
lateral_referencers = NULL;
234+
foreach(lc, root->lateral_info_list)
235+
{
236+
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc);
237+
238+
if (bms_is_member(rel->relid, ljinfo->lateral_lhs))
239+
lateral_referencers = bms_add_member(lateral_referencers,
240+
ljinfo->lateral_rhs);
241+
}
242+
223243
/* Bitmap paths are collected and then dealt with at the end */
224244
bitindexpaths = bitjoinpaths = joinorclauses = NIL;
225245

226246
/* Examine each index in turn */
227-
foreach(ilist, rel->indexlist)
247+
foreach(lc, rel->indexlist)
228248
{
229-
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
249+
IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
230250

231251
/* Protect limited-size array in IndexClauseSets */
232252
Assert(index->ncolumns <= INDEX_MAX_KEYS);
@@ -260,15 +280,16 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
260280
* EquivalenceClasses. Also, collect join OR clauses for later.
261281
*/
262282
MemSet(&jclauseset, 0, sizeof(jclauseset));
263-
match_join_clauses_to_index(root, rel, index,
283+
match_join_clauses_to_index(root, rel, index, lateral_referencers,
264284
&jclauseset, &joinorclauses);
265285

266286
/*
267287
* Look for EquivalenceClasses that can generate joinclauses matching
268288
* the index.
269289
*/
270290
MemSet(&eclauseset, 0, sizeof(eclauseset));
271-
match_eclass_clauses_to_index(root, index, &eclauseset);
291+
match_eclass_clauses_to_index(root, index, lateral_referencers,
292+
&eclauseset);
272293

273294
/*
274295
* If we found any plain or eclass join clauses, decide what to do
@@ -1796,6 +1817,7 @@ match_restriction_clauses_to_index(RelOptInfo *rel, IndexOptInfo *index,
17961817
static void
17971818
match_join_clauses_to_index(PlannerInfo *root,
17981819
RelOptInfo *rel, IndexOptInfo *index,
1820+
Relids lateral_referencers,
17991821
IndexClauseSet *clauseset,
18001822
List **joinorclauses)
18011823
{
@@ -1810,6 +1832,10 @@ match_join_clauses_to_index(PlannerInfo *root,
18101832
if (!join_clause_is_movable_to(rinfo, rel->relid))
18111833
continue;
18121834

1835+
/* Not useful if it conflicts with any LATERAL references */
1836+
if (bms_overlap(rinfo->clause_relids, lateral_referencers))
1837+
continue;
1838+
18131839
/* Potentially usable, so see if it matches the index or is an OR */
18141840
if (restriction_is_or_clause(rinfo))
18151841
*joinorclauses = lappend(*joinorclauses, rinfo);
@@ -1825,6 +1851,7 @@ match_join_clauses_to_index(PlannerInfo *root,
18251851
*/
18261852
static void
18271853
match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index,
1854+
Relids lateral_referencers,
18281855
IndexClauseSet *clauseset)
18291856
{
18301857
int indexcol;
@@ -1837,9 +1864,11 @@ match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index,
18371864
{
18381865
List *clauses;
18391866

1867+
/* Generate clauses, skipping any that join to lateral_referencers */
18401868
clauses = generate_implied_equalities_for_indexcol(root,
18411869
index,
1842-
indexcol);
1870+
indexcol,
1871+
lateral_referencers);
18431872

18441873
/*
18451874
* We have to check whether the results actually do match the index,

src/include/optimizer/paths.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ extern void mutate_eclass_expressions(PlannerInfo *root,
127127
void *context);
128128
extern List *generate_implied_equalities_for_indexcol(PlannerInfo *root,
129129
IndexOptInfo *index,
130-
int indexcol);
130+
int indexcol,
131+
Relids prohibited_rels);
131132
extern bool have_relevant_eclass_joinclause(PlannerInfo *root,
132133
RelOptInfo *rel1, RelOptInfo *rel2);
133134
extern bool has_relevant_eclass_joinclause(PlannerInfo *root,

0 commit comments

Comments
 (0)