|
8 | 8 | * |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.78 2005/11/28 17:14:23 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.79 2005/11/28 23:46:03 tgl Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
@@ -120,16 +120,28 @@ ExecHashJoin(HashJoinState *node) |
120 | 120 | * since we aren't going to be able to skip the join on the strength |
121 | 121 | * of an empty inner relation anyway.) |
122 | 122 | * |
| 123 | + * If we are rescanning the join, we make use of information gained |
| 124 | + * on the previous scan: don't bother to try the prefetch if the |
| 125 | + * previous scan found the outer relation nonempty. This is not |
| 126 | + * 100% reliable since with new parameters the outer relation might |
| 127 | + * yield different results, but it's a good heuristic. |
| 128 | + * |
123 | 129 | * The only way to make the check is to try to fetch a tuple from the |
124 | 130 | * outer plan node. If we succeed, we have to stash it away for later |
125 | 131 | * consumption by ExecHashJoinOuterGetTuple. |
126 | 132 | */ |
127 | | - if (outerNode->plan->startup_cost < hashNode->ps.plan->total_cost || |
128 | | - node->js.jointype == JOIN_LEFT) |
| 133 | + if (node->js.jointype == JOIN_LEFT || |
| 134 | + (outerNode->plan->startup_cost < hashNode->ps.plan->total_cost && |
| 135 | + !node->hj_OuterNotEmpty)) |
129 | 136 | { |
130 | 137 | node->hj_FirstOuterTupleSlot = ExecProcNode(outerNode); |
131 | 138 | if (TupIsNull(node->hj_FirstOuterTupleSlot)) |
| 139 | + { |
| 140 | + node->hj_OuterNotEmpty = false; |
132 | 141 | return NULL; |
| 142 | + } |
| 143 | + else |
| 144 | + node->hj_OuterNotEmpty = true; |
133 | 145 | } |
134 | 146 | else |
135 | 147 | node->hj_FirstOuterTupleSlot = NULL; |
@@ -159,6 +171,13 @@ ExecHashJoin(HashJoinState *node) |
159 | 171 | * scanning the outer relation |
160 | 172 | */ |
161 | 173 | hashtable->nbatch_outstart = hashtable->nbatch; |
| 174 | + |
| 175 | + /* |
| 176 | + * Reset OuterNotEmpty for scan. (It's OK if we fetched a tuple |
| 177 | + * above, because ExecHashJoinOuterGetTuple will immediately |
| 178 | + * set it again.) |
| 179 | + */ |
| 180 | + node->hj_OuterNotEmpty = false; |
162 | 181 | } |
163 | 182 |
|
164 | 183 | /* |
@@ -454,6 +473,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate) |
454 | 473 | hjstate->js.ps.ps_TupFromTlist = false; |
455 | 474 | hjstate->hj_NeedNewOuter = true; |
456 | 475 | hjstate->hj_MatchedOuter = false; |
| 476 | + hjstate->hj_OuterNotEmpty = false; |
457 | 477 |
|
458 | 478 | return hjstate; |
459 | 479 | } |
@@ -546,6 +566,9 @@ ExecHashJoinOuterGetTuple(PlanState *outerNode, |
546 | 566 | *hashvalue = ExecHashGetHashValue(hashtable, econtext, |
547 | 567 | hjstate->hj_OuterHashKeys); |
548 | 568 |
|
| 569 | + /* remember outer relation is not empty for possible rescan */ |
| 570 | + hjstate->hj_OuterNotEmpty = true; |
| 571 | + |
549 | 572 | return slot; |
550 | 573 | } |
551 | 574 |
|
@@ -809,7 +832,19 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) |
809 | 832 | if (node->hj_HashTable->nbatch == 1 && |
810 | 833 | ((PlanState *) node)->righttree->chgParam == NULL) |
811 | 834 | { |
812 | | - /* okay to reuse the hash table; needn't rescan inner, either */ |
| 835 | + /* |
| 836 | + * okay to reuse the hash table; needn't rescan inner, either. |
| 837 | + * |
| 838 | + * What we do need to do is reset our state about the emptiness |
| 839 | + * of the outer relation, so that the new scan of the outer will |
| 840 | + * update it correctly if it turns out to be empty this time. |
| 841 | + * (There's no harm in clearing it now because ExecHashJoin won't |
| 842 | + * need the info. In the other cases, where the hash table |
| 843 | + * doesn't exist or we are destroying it, we leave this state |
| 844 | + * alone because ExecHashJoin will need it the first time |
| 845 | + * through.) |
| 846 | + */ |
| 847 | + node->hj_OuterNotEmpty = false; |
813 | 848 | } |
814 | 849 | else |
815 | 850 | { |
|
0 commit comments