From 40ffbd2d9ee5954e5ae09f1e5a929ae2f2b17b8c Mon Sep 17 00:00:00 2001 From: "Andrey V. Lepikhov" Date: Mon, 9 Dec 2019 18:25:04 +0500 Subject: [PATCH] Skip scan of outer subtree if inner of the NestedLoop node is guaranteed empty. --- src/backend/executor/nodeMaterial.c | 11 +++++++++++ src/backend/executor/nodeNestloop.c | 5 +++++ src/include/nodes/execnodes.h | 4 ++++ src/test/regress/expected/partition_prune.out | 8 ++++---- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index cc93bbe45b..98771647f6 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -135,6 +135,8 @@ ExecMaterial(PlanState *pstate) if (TupIsNull(outerslot)) { node->eof_underlying = true; + if (tuplestorestate && tuplestore_tuple_count(tuplestorestate) == 0) + node->ss.ps.guaranteed_empty = true; return NULL; } @@ -348,6 +350,9 @@ ExecReScanMaterial(MaterialState *node) node->tuplestorestate = NULL; if (outerPlan->chgParam == NULL) ExecReScan(outerPlan); + else + /* At first look no cases can lead to this code. But still. */ + node->ss.ps.guaranteed_empty = false; node->eof_underlying = false; } else @@ -363,6 +368,12 @@ ExecReScanMaterial(MaterialState *node) */ if (outerPlan->chgParam == NULL) ExecReScan(outerPlan); + + /* + * The node suppress tuplestore and guaranteed_empty trick isn't work. + */ + Assert(node->ss.ps.guaranteed_empty == false); + node->eof_underlying = false; } } diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index fc6667ef82..ea26a7d9d1 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -164,6 +164,11 @@ ExecNestLoop(PlanState *pstate) { ENL1_printf("no inner tuple, need new outer tuple"); + if (innerPlan->guaranteed_empty && + (node->js.jointype == JOIN_INNER || + node->js.jointype == JOIN_SEMI)) + return NULL; + node->nl_NeedNewOuter = true; if (!node->nl_MatchedOuter && diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 692438d6df..c7f1a14526 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1007,6 +1007,9 @@ typedef struct PlanState * ExecConditionalAssignProjectionInfo()). If no projection is necessary * ExecConditionalAssignProjectionInfo() defaults those fields to the scan * operations. + * + * If guaranteed_empty field is true, this means that no tuple will be + * returned by the node. */ const TupleTableSlotOps *scanops; const TupleTableSlotOps *outerops; @@ -1020,6 +1023,7 @@ typedef struct PlanState bool outeropsset; bool inneropsset; bool resultopsset; + bool guaranteed_empty; } PlanState; /* ---------------- diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index f9eeda60e6..04cfe0944e 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -2455,9 +2455,9 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; Heap Blocks: exact=1 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_2 (actual rows=0 loops=1) + -> Bitmap Heap Scan on ab_a1_b3 ab_2 (never executed) Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=0 loops=1) + -> Bitmap Index Scan on ab_a1_b3_a_idx (never executed) Index Cond: (a = 1) -> Materialize (actual rows=0 loops=1) -> Bitmap Heap Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1) @@ -2496,9 +2496,9 @@ update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; Heap Blocks: exact=1 -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_2 (actual rows=0 loops=1) + -> Bitmap Heap Scan on ab_a1_b3 ab_2 (never executed) Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) + -> Bitmap Index Scan on ab_a1_b3_a_idx (never executed) Index Cond: (a = 1) -> Materialize (actual rows=0 loops=1) -> Bitmap Heap Scan on ab_a1_b3 ab_a1_3 (actual rows=0 loops=1) -- 2.17.1