Hello Tom,

I tried both patches on a different machine (but had to take the patches from 
cvs diff, cut'n paste from the mail-program did not work). Up until now, they 
work like a charm, correct results and fast. I will try on the other machine 
that failed yesterday in the afternoon, maybe it was just a problem with 
patching (or with the machine setup itself, it's a hardened gentoo, but I doubt 
that).

BTW: the difference of the second patch is really noticable, from 990ms down to 
226ms.

Thanks for your quick response! I wish commercial vendors would act that fast 
:-)

Best regards,
        Mario Weilguni



icomedias - Digitale Kommunikation
------------------------------------------------------------------------
Mario Weilguni, Forschung und Entwicklung
[EMAIL PROTECTED], http://www.icomedias.com/

icomedias Österreich Systemhaus GmbH:
  8020 Graz, Entenplatz 1 
  Tel: +43 (316) 721.671-272, Fax: -103  

icomedias Deutschland Systemhaus GmbH:
  10969 Berlin, Alexandrinenstraße 2-3
  Tel: +49 (30) 695.399-272, Fax: -103

-----Original Message-----
From: Tom Lane [mailto:[EMAIL PROTECTED] 
Sent: Tuesday, November 29, 2005 12:50 AM
To: Mario Weilguni; pgsql-hackers@postgresql.org
Subject: Re: Hashjoin startup strategy (was Re: [HACKERS] Getting different 
number of results when using hashjoin on/off) 

I wrote:
> For a query like this, where the hash join is being done repeatedly,
> it might be useful for the executor itself to track how often each
> subplan has been seen to be empty.

I implemented a simple form of this, and it made 8.1 faster than 8.0
on the test case I was using.  Give it a try ...

                        regards, tom lane


Index: src/backend/executor/nodeHashjoin.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v
retrieving revision 1.75.2.2
diff -c -r1.75.2.2 nodeHashjoin.c
*** src/backend/executor/nodeHashjoin.c 28 Nov 2005 17:14:47 -0000      1.75.2.2
--- src/backend/executor/nodeHashjoin.c 28 Nov 2005 23:41:28 -0000
***************
*** 120,135 ****
                 * since we aren't going to be able to skip the join on the 
strength
                 * of an empty inner relation anyway.)
                 *
                 * The only way to make the check is to try to fetch a tuple 
from the
                 * outer plan node.  If we succeed, we have to stash it away 
for later
                 * consumption by ExecHashJoinOuterGetTuple.
                 */
!               if (outerNode->plan->startup_cost < 
hashNode->ps.plan->total_cost ||
!                       node->js.jointype == JOIN_LEFT)
                {
                        node->hj_FirstOuterTupleSlot = ExecProcNode(outerNode);
                        if (TupIsNull(node->hj_FirstOuterTupleSlot))
                                return NULL;
                }
                else
                        node->hj_FirstOuterTupleSlot = NULL;
--- 120,147 ----
                 * since we aren't going to be able to skip the join on the 
strength
                 * of an empty inner relation anyway.)
                 *
+                * If we are rescanning the join, we make use of information 
gained
+                * on the previous scan: don't bother to try the prefetch if the
+                * previous scan found the outer relation nonempty.  This is not
+                * 100% reliable since with new parameters the outer relation 
might
+                * yield different results, but it's a good heuristic.
+                *
                 * The only way to make the check is to try to fetch a tuple 
from the
                 * outer plan node.  If we succeed, we have to stash it away 
for later
                 * consumption by ExecHashJoinOuterGetTuple.
                 */
!               if (node->js.jointype == JOIN_LEFT ||
!                       (outerNode->plan->startup_cost < 
hashNode->ps.plan->total_cost &&
!                        !node->hj_OuterNotEmpty))
                {
                        node->hj_FirstOuterTupleSlot = ExecProcNode(outerNode);
                        if (TupIsNull(node->hj_FirstOuterTupleSlot))
+                       {
+                               node->hj_OuterNotEmpty = false;
                                return NULL;
+                       }
+                       else
+                               node->hj_OuterNotEmpty = true;
                }
                else
                        node->hj_FirstOuterTupleSlot = NULL;
***************
*** 159,164 ****
--- 171,183 ----
                 * scanning the outer relation
                 */
                hashtable->nbatch_outstart = hashtable->nbatch;
+ 
+               /*
+                * Reset OuterNotEmpty for scan.  (It's OK if we fetched a tuple
+                * above, because ExecHashJoinOuterGetTuple will immediately
+                * set it again.)
+                */
+               node->hj_OuterNotEmpty = false;
        }
  
        /*
***************
*** 454,459 ****
--- 473,479 ----
        hjstate->js.ps.ps_TupFromTlist = false;
        hjstate->hj_NeedNewOuter = true;
        hjstate->hj_MatchedOuter = false;
+       hjstate->hj_OuterNotEmpty = false;
  
        return hjstate;
  }
***************
*** 546,551 ****
--- 566,574 ----
                        *hashvalue = ExecHashGetHashValue(hashtable, econtext,
                                                                                
          hjstate->hj_OuterHashKeys);
  
+                       /* remember outer relation is not empty for possible 
rescan */
+                       hjstate->hj_OuterNotEmpty = true;
+ 
                        return slot;
                }
  
***************
*** 810,816 ****
                if (node->hj_HashTable->nbatch == 1 &&
                        ((PlanState *) node)->righttree->chgParam == NULL)
                {
!                       /* okay to reuse the hash table; needn't rescan inner, 
either */
                }
                else
                {
--- 833,851 ----
                if (node->hj_HashTable->nbatch == 1 &&
                        ((PlanState *) node)->righttree->chgParam == NULL)
                {
!                       /*
!                        * okay to reuse the hash table; needn't rescan inner, 
either.
!                        *
!                        * What we do need to do is reset our state about the 
emptiness
!                        * of the outer relation, so that the new scan of the 
outer will
!                        * update it correctly if it turns out to be empty this 
time.
!                        * (There's no harm in clearing it now because 
ExecHashJoin won't
!                        * need the info.  In the other cases, where the hash 
table
!                        * doesn't exist or we are destroying it, we leave this 
state
!                        * alone because ExecHashJoin will need it the first 
time
!                        * through.)
!                        */
!                       node->hj_OuterNotEmpty = false;
                }
                else
                {
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.139.2.2
diff -c -r1.139.2.2 execnodes.h
*** src/include/nodes/execnodes.h       22 Nov 2005 18:23:28 -0000      
1.139.2.2
--- src/include/nodes/execnodes.h       28 Nov 2005 23:41:28 -0000
***************
*** 1101,1106 ****
--- 1101,1107 ----
   *            hj_FirstOuterTupleSlot  first tuple retrieved from outer plan
   *            hj_NeedNewOuter                 true if need new outer tuple on 
next call
   *            hj_MatchedOuter                 true if found a join match for 
current outer
+  *            hj_OuterNotEmpty                true if outer relation known 
not empty
   * ----------------
   */
  
***************
*** 1125,1130 ****
--- 1126,1132 ----
        TupleTableSlot *hj_FirstOuterTupleSlot;
        bool            hj_NeedNewOuter;
        bool            hj_MatchedOuter;
+       bool            hj_OuterNotEmpty;
  } HashJoinState;
  
  

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to