Avoid unnecessary shm writes in Parallel Hash Join.
authorThomas Munro <tmunro@postgresql.org>
Sun, 26 Jan 2020 23:52:08 +0000 (12:52 +1300)
committerThomas Munro <tmunro@postgresql.org>
Mon, 27 Jan 2020 02:07:03 +0000 (15:07 +1300)
Currently, Parallel Hash Join cannot be used for full/right joins,
so there is no point in setting the match flag.  It turns out that
the cache coherence traffic generated by those writes slows down
large systems running many-core joins, so let's stop doing that.
In future, if we need to use match bits in parallel joins, we might
want to consider setting them only if not already set.

Back-patch to 11, where Parallel Hash Join arrived.

Reported-by: Deng, Gang
Discussion: https://postgr.es/m/0F44E799048C4849BAE4B91012DB910462E9897A%40SHSMSX103.ccr.corp.intel.com

src/backend/executor/nodeHashjoin.c

index 67c717910f5c2d2ba9720d08df2b6bf3e3c8720b..c901a8092366c46cd18752c8b9ab1dab2c8929bb 100644 (file)
@@ -454,7 +454,26 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
                if (joinqual == NULL || ExecQual(joinqual, econtext))
                {
                    node->hj_MatchedOuter = true;
-                   HeapTupleHeaderSetMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple));
+
+                   if (parallel)
+                   {
+                       /*
+                        * Full/right outer joins are currently not supported
+                        * for parallel joins, so we don't need to set the
+                        * match bit.  Experiments show that it's worth
+                        * avoiding the shared memory traffic on large
+                        * systems.
+                        */
+                       Assert(!HJ_FILL_INNER(node));
+                   }
+                   else
+                   {
+                       /*
+                        * This is really only needed if HJ_FILL_INNER(node),
+                        * but we'll avoid the branch and just set it always.
+                        */
+                       HeapTupleHeaderSetMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple));
+                   }
 
                    /* In an antijoin, we never return a matched tuple */
                    if (node->js.jointype == JOIN_ANTI)