]> granicus.if.org Git - postgresql/commitdiff
Performance fix for new anti-join code in nodeMergejoin.c: after finding a
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 15 Aug 2008 19:20:42 +0000 (19:20 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 15 Aug 2008 19:20:42 +0000 (19:20 +0000)
match in antijoin mode, we should advance to next outer tuple not next inner.
We know we don't want to return this outer tuple, and there is no point in
advancing over matching inner tuples now, because we'd just have to do it
again if the next outer tuple has the same merge key.  This makes a noticeable
difference if there are lots of duplicate keys in both inputs.

Similarly, after finding a match in semijoin mode, arrange to advance to
the next outer tuple after returning the current match; or immediately,
if it fails the extra quals.  The rationale is the same.  (This is a
performance bug in existing releases; perhaps worth back-patching?  The
planner tries to avoid using mergejoin with lots of duplicates, so it may
not be a big issue in practice.)

Nestloop and hash got this right to start with, but I made some cosmetic
adjustments there to make the corresponding bits of logic look more similar.

src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeMergejoin.c
src/backend/executor/nodeNestloop.c

index 837837bece0c69c53576b014048d79aa2a784266..4534845b5272e583fdb8810966cf5649c72ff3b0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.94 2008/08/14 18:47:58 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.95 2008/08/15 19:20:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -264,36 +264,34 @@ ExecHashJoin(HashJoinState *node)
                                        node->hj_NeedNewOuter = true;
                                        break;          /* out of loop over hash bucket */
                                }
-                               else
+
+                               /*
+                                * In a semijoin, we'll consider returning the first match,
+                                * but after that we're done with this outer tuple.
+                                */
+                               if (node->js.jointype == JOIN_SEMI)
+                                       node->hj_NeedNewOuter = true;
+
+                               if (otherqual == NIL || ExecQual(otherqual, econtext, false))
                                {
-                                       /*
-                                        * In a semijoin, we'll consider returning the first match,
-                                        * but after that we're done with this outer tuple.
-                                        */
-                                       if (node->js.jointype == JOIN_SEMI)
-                                               node->hj_NeedNewOuter = true;
-
-                                       if (otherqual == NIL || ExecQual(otherqual, econtext, false))
-                                       {
-                                               TupleTableSlot *result;
+                                       TupleTableSlot *result;
 
-                                               result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
+                                       result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
 
-                                               if (isDone != ExprEndResult)
-                                               {
-                                                       node->js.ps.ps_TupFromTlist =
-                                                               (isDone == ExprMultipleResult);
-                                                       return result;
-                                               }
+                                       if (isDone != ExprEndResult)
+                                       {
+                                               node->js.ps.ps_TupFromTlist =
+                                                       (isDone == ExprMultipleResult);
+                                               return result;
                                        }
-
-                                       /*
-                                        * If semijoin and we didn't return the tuple, we're still
-                                        * done with this outer tuple.
-                                        */
-                                       if (node->js.jointype == JOIN_SEMI)
-                                               break;          /* out of loop over hash bucket */
                                }
+
+                               /*
+                                * If semijoin and we didn't return the tuple, we're still
+                                * done with this outer tuple.
+                                */
+                               if (node->js.jointype == JOIN_SEMI)
+                                       break;          /* out of loop over hash bucket */
                        }
                }
 
index e9deb5c8da7ca01e0ff8457ea2d7252545144797..d460349ad4505a36aec8df35dffed08788091062 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.92 2008/08/14 18:47:58 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.93 2008/08/15 19:20:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -757,15 +757,9 @@ ExecMergeJoin(MergeJoinState *node)
                                innerTupleSlot = node->mj_InnerTupleSlot;
                                econtext->ecxt_innertuple = innerTupleSlot;
 
-                               if (node->js.jointype == JOIN_SEMI &&
-                                       node->mj_MatchedOuter)
-                                       qualResult = false;
-                               else
-                               {
-                                       qualResult = (joinqual == NIL ||
-                                                                 ExecQual(joinqual, econtext, false));
-                                       MJ_DEBUG_QUAL(joinqual, qualResult);
-                               }
+                               qualResult = (joinqual == NIL ||
+                                                         ExecQual(joinqual, econtext, false));
+                               MJ_DEBUG_QUAL(joinqual, qualResult);
 
                                if (qualResult)
                                {
@@ -774,7 +768,17 @@ ExecMergeJoin(MergeJoinState *node)
 
                                        /* In an antijoin, we never return a matched tuple */
                                        if (node->js.jointype == JOIN_ANTI)
+                                       {
+                                               node->mj_JoinState = EXEC_MJ_NEXTOUTER;
                                                break;
+                                       }
+
+                                       /*
+                                        * In a semijoin, we'll consider returning the first match,
+                                        * but after that we're done with this outer tuple.
+                                        */
+                                       if (node->js.jointype == JOIN_SEMI)
+                                               node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
                                        qualResult = (otherqual == NIL ||
                                                                  ExecQual(otherqual, econtext, false));
index c6a33228582c24e138a7b2e534b3fa853fa29524..27e3582649ec7382e6d1466faab5f48b2b644c02 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.47 2008/08/14 18:47:58 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.48 2008/08/15 19:20:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -226,35 +226,36 @@ ExecNestLoop(NestLoopState *node)
 
                        /* In an antijoin, we never return a matched tuple */
                        if (node->js.jointype == JOIN_ANTI)
+                       {
                                node->nl_NeedNewOuter = true;
-                       else
+                               continue;               /* return to top of loop */
+                       }
+
+                       /*
+                        * In a semijoin, we'll consider returning the first match,
+                        * but after that we're done with this outer tuple.
+                        */
+                       if (node->js.jointype == JOIN_SEMI)
+                               node->nl_NeedNewOuter = true;
+
+                       if (otherqual == NIL || ExecQual(otherqual, econtext, false))
                        {
                                /*
-                                * In a semijoin, we'll consider returning the first match,
-                                * but after that we're done with this outer tuple.
+                                * qualification was satisfied so we project and return the
+                                * slot containing the result tuple using ExecProject().
                                 */
-                               if (node->js.jointype == JOIN_SEMI)
-                                       node->nl_NeedNewOuter = true;
-                               if (otherqual == NIL || ExecQual(otherqual, econtext, false))
-                               {
-                                       /*
-                                        * qualification was satisfied so we project and return
-                                        * the slot containing the result tuple using
-                                        * ExecProject().
-                                        */
-                                       TupleTableSlot *result;
-                                       ExprDoneCond isDone;
+                               TupleTableSlot *result;
+                               ExprDoneCond isDone;
 
-                                       ENL1_printf("qualification succeeded, projecting tuple");
+                               ENL1_printf("qualification succeeded, projecting tuple");
 
-                                       result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
+                               result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
 
-                                       if (isDone != ExprEndResult)
-                                       {
-                                               node->js.ps.ps_TupFromTlist =
-                                                       (isDone == ExprMultipleResult);
-                                               return result;
-                                       }
+                               if (isDone != ExprEndResult)
+                               {
+                                       node->js.ps.ps_TupFromTlist =
+                                               (isDone == ExprMultipleResult);
+                                       return result;
                                }
                        }
                }