v2-lazy-join.diff
text/x-patch
Filename: v2-lazy-join.diff
Type: text/x-patch
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/executor/nodeNestloop.c | 13 | 2 |
| src/backend/optimizer/plan/createplan.c | 26 | 1 |
| src/backend/optimizer/plan/setrefs.c | 8 | 0 |
| src/backend/optimizer/util/pathnode.c | 7 | 0 |
| src/include/nodes/execnodes.h | 1 | 0 |
| src/include/nodes/pathnodes.h | 1 | 1 |
| src/include/nodes/plannodes.h | 2 | 1 |
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 7f4bf6c4db..fd80dc2192 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -66,6 +66,7 @@ ExecNestLoop(PlanState *pstate)
TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot;
ExprState *joinqual;
+ ExprState *rhs_joinqual;
ExprState *otherqual;
ExprContext *econtext;
ListCell *lc;
@@ -79,6 +80,7 @@ ExecNestLoop(PlanState *pstate)
nl = (NestLoop *) node->js.ps.plan;
joinqual = node->js.joinqual;
+ rhs_joinqual = node->js.rhs_joinqual;
otherqual = node->js.ps.qual;
outerPlan = outerPlanState(node);
innerPlan = innerPlanState(node);
@@ -156,8 +158,15 @@ ExecNestLoop(PlanState *pstate)
*/
ENL1_printf("getting new inner tuple");
- innerTupleSlot = ExecProcNode(innerPlan);
- econtext->ecxt_innertuple = innerTupleSlot;
+ if (rhs_joinqual && !ExecQual(rhs_joinqual, econtext))
+ {
+ innerTupleSlot = NULL;
+ }
+ else
+ {
+ innerTupleSlot = ExecProcNode(innerPlan);
+ econtext->ecxt_innertuple = innerTupleSlot;
+ }
if (TupIsNull(innerTupleSlot))
{
@@ -314,6 +323,8 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
nlstate->js.jointype = node->join.jointype;
nlstate->js.joinqual =
ExecInitQual(node->join.joinqual, (PlanState *) nlstate);
+ nlstate->js.rhs_joinqual =
+ ExecInitQual(node->join.rhs_joinqual, (PlanState *) nlstate);
/*
* detect whether we need only consider the first matching inner tuple
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index f2ed0d81f6..003f949547 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -232,7 +232,7 @@ static RecursiveUnion *make_recursive_union(List *tlist,
static BitmapAnd *make_bitmap_and(List *bitmapplans);
static BitmapOr *make_bitmap_or(List *bitmapplans);
static NestLoop *make_nestloop(List *tlist,
- List *joinclauses, List *otherclauses, List *nestParams,
+ List *joinclauses, List *rhs_joinclauses, List *otherclauses, List *nestParams,
Plan *lefttree, Plan *righttree,
JoinType jointype, bool inner_unique);
static HashJoin *make_hashjoin(List *tlist,
@@ -4352,6 +4352,7 @@ create_nestloop_plan(PlannerInfo *root,
Plan *inner_plan;
List *tlist = build_path_tlist(root, &best_path->jpath.path);
List *joinrestrictclauses = best_path->jpath.joinrestrictinfo;
+ List *rhs_joinclauses = NIL;
List *joinclauses;
List *otherclauses;
Relids outerrelids;
@@ -4390,6 +4391,11 @@ create_nestloop_plan(PlannerInfo *root,
/* Sort join qual clauses into best execution order */
joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses);
+ foreach_node(RestrictInfo, rinfo, best_path->jpath.rhs_joinrinfo)
+ {
+ rhs_joinclauses = lappend(rhs_joinclauses, rinfo->clause);
+ }
+
/* Get the join qual clauses (in plain expression form) */
/* Any pseudoconstant clauses are ignored here */
if (IS_OUTER_JOIN(best_path->jpath.jointype))
@@ -4423,6 +4429,7 @@ create_nestloop_plan(PlannerInfo *root,
join_plan = make_nestloop(tlist,
joinclauses,
+ rhs_joinclauses,
otherclauses,
nestParams,
outer_plan,
@@ -6021,6 +6028,7 @@ make_bitmap_or(List *bitmapplans)
static NestLoop *
make_nestloop(List *tlist,
List *joinclauses,
+ List *rhs_joinclauses,
List *otherclauses,
List *nestParams,
Plan *lefttree,
@@ -6038,6 +6046,23 @@ make_nestloop(List *tlist,
node->join.jointype = jointype;
node->join.inner_unique = inner_unique;
node->join.joinqual = joinclauses;
+
+ {
+ ListCell *lc;
+
+ foreach(lc, node->join.joinqual)
+ {
+ Node *qual = (Node *) lfirst(lc);
+
+ if (!list_member(rhs_joinclauses, qual))
+ continue;
+
+ node->join.joinqual = foreach_delete_current(node->join.joinqual, lc);
+ }
+
+ }
+
+ node->join.rhs_joinqual = rhs_joinclauses;
node->nestParams = nestParams;
return node;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 91c7c4fe2f..0f54450ead 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -2294,6 +2294,14 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
rtoffset,
NRM_EQUAL,
NUM_EXEC_QUAL((Plan *) join));
+ join->rhs_joinqual = fix_join_expr(root,
+ join->rhs_joinqual,
+ outer_itlist,
+ inner_itlist,
+ (Index) 0,
+ rtoffset,
+ NRM_EQUAL,
+ NUM_EXEC_QUAL((Plan *) join));
/* Now do join-type-specific stuff */
if (IsA(join, NestLoop))
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index fc97bf6ee2..b7f1dbac23 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -2603,6 +2603,13 @@ create_nestloop_path(PlannerInfo *root,
pathnode->jpath.innerjoinpath = inner_path;
pathnode->jpath.joinrestrictinfo = restrict_clauses;
+ foreach_node(RestrictInfo, rinfo, restrict_clauses)
+ {
+ if (bms_is_subset(rinfo->clause_relids, outer_path->parent->relids))
+ pathnode->jpath.rhs_joinrinfo =
+ lappend(pathnode->jpath.rhs_joinrinfo, rinfo);
+ }
+
final_cost_nestloop(root, pathnode, workspace, extra);
return pathnode;
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 182a6956bb..14c7610c8c 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2125,6 +2125,7 @@ typedef struct JoinState
bool single_match; /* True if we should skip to next outer tuple
* after finding one inner match */
ExprState *joinqual; /* JOIN quals (in addition to ps.qual) */
+ ExprState *rhs_joinqual;
} JoinState;
/* ----------------
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index add0f9e45f..c28c23c983 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -2085,7 +2085,7 @@ typedef struct JoinPath
Path *innerjoinpath; /* path for the inner side of the join */
List *joinrestrictinfo; /* RestrictInfos to apply to join */
-
+ List *rhs_joinrinfo; /* Outer-side join clauses (filters) */
/*
* See the notes for RelOptInfo and ParamPathInfo to understand why
* joinrestrictinfo is needed in JoinPath, and can't be merged into the
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 52f29bcdb6..2c90a63e59 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -791,7 +791,8 @@ typedef struct Join
Plan plan;
JoinType jointype;
bool inner_unique;
- List *joinqual; /* JOIN quals (in addition to plan.qual) */
+ List *joinqual;
+ List *rhs_joinqual; /* JOIN quals (in addition to plan.qual) */
} Join;
/* ----------------