1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-03 20:02:46 +03:00

Upgrade planner and executor to allow multiple hash keys for a hash join,

instead of only one.  This should speed up planning (only one hash path
to consider for a given pair of relations) as well as allow more effective
hashing, when there are multiple hashable joinclauses.
This commit is contained in:
Tom Lane
2002-11-30 00:08:22 +00:00
parent f68f11928d
commit ddb2d78de0
14 changed files with 182 additions and 133 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.67 2002/11/06 22:31:23 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.68 2002/11/30 00:08:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,7 +45,7 @@ ExecHash(Hash *node)
EState *estate;
HashState *hashstate;
Plan *outerNode;
Node *hashkey;
List *hashkeys;
HashJoinTable hashtable;
TupleTableSlot *slot;
ExprContext *econtext;
@ -79,7 +79,7 @@ ExecHash(Hash *node)
/*
* set expression context
*/
hashkey = node->hashkey;
hashkeys = node->hashkeys;
econtext = hashstate->cstate.cs_ExprContext;
/*
@ -91,7 +91,7 @@ ExecHash(Hash *node)
if (TupIsNull(slot))
break;
econtext->ecxt_innertuple = slot;
ExecHashTableInsert(hashtable, econtext, hashkey);
ExecHashTableInsert(hashtable, econtext, hashkeys);
ExecClearTuple(slot);
}
@ -212,7 +212,9 @@ ExecHashTableCreate(Hash *node)
int totalbuckets;
int nbuckets;
int nbatch;
int nkeys;
int i;
List *hk;
MemoryContext oldcxt;
/*
@ -248,11 +250,19 @@ ExecHashTableCreate(Hash *node)
hashtable->outerBatchSize = NULL;
/*
* Get info about the datatype of the hash key.
* Get info about the datatypes of the hash keys.
*/
get_typlenbyval(exprType(node->hashkey),
&hashtable->typLen,
&hashtable->typByVal);
nkeys = length(node->hashkeys);
hashtable->typLens = (int16 *) palloc(nkeys * sizeof(int16));
hashtable->typByVals = (bool *) palloc(nkeys * sizeof(bool));
i = 0;
foreach(hk, node->hashkeys)
{
get_typlenbyval(exprType(lfirst(hk)),
&hashtable->typLens[i],
&hashtable->typByVals[i]);
i++;
}
/*
* Create temporary memory contexts in which to keep the hashtable
@ -465,9 +475,9 @@ ExecHashTableDestroy(HashJoinTable hashtable)
void
ExecHashTableInsert(HashJoinTable hashtable,
ExprContext *econtext,
Node *hashkey)
List *hashkeys)
{
int bucketno = ExecHashGetBucket(hashtable, econtext, hashkey);
int bucketno = ExecHashGetBucket(hashtable, econtext, hashkeys);
TupleTableSlot *slot = econtext->ecxt_innertuple;
HeapTuple heapTuple = slot->val;
@ -522,44 +532,55 @@ ExecHashTableInsert(HashJoinTable hashtable,
int
ExecHashGetBucket(HashJoinTable hashtable,
ExprContext *econtext,
Node *hashkey)
List *hashkeys)
{
uint32 hashkey = 0;
int bucketno;
Datum keyval;
bool isNull;
List *hk;
int i = 0;
MemoryContext oldContext;
/*
* We reset the eval context each time to reclaim any memory leaked in
* the hashkey expression or ComputeHashFunc itself.
* the hashkey expressions or ComputeHashFunc itself.
*/
ResetExprContext(econtext);
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
/*
* Get the join attribute value of the tuple
*/
keyval = ExecEvalExpr(hashkey, econtext, &isNull, NULL);
/*
* Compute the hash function
*/
if (isNull)
bucketno = 0;
else
foreach(hk, hashkeys)
{
bucketno = ComputeHashFunc(keyval,
(int) hashtable->typLen,
hashtable->typByVal)
% (uint32) hashtable->totalbuckets;
Datum keyval;
bool isNull;
/* rotate hashkey left 1 bit at each step */
hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
/*
* Get the join attribute value of the tuple
*/
keyval = ExecEvalExpr(lfirst(hk), econtext, &isNull, NULL);
/*
* Compute the hash function
*/
if (!isNull) /* treat nulls as having hash key 0 */
{
hashkey ^= ComputeHashFunc(keyval,
(int) hashtable->typLens[i],
hashtable->typByVals[i]);
}
i++;
}
bucketno = hashkey % (uint32) hashtable->totalbuckets;
#ifdef HJDEBUG
if (bucketno >= hashtable->nbuckets)
printf("hash(%ld) = %d SAVED\n", (long) keyval, bucketno);
printf("hash(%u) = %d SAVED\n", hashkey, bucketno);
else
printf("hash(%ld) = %d\n", (long) keyval, bucketno);
printf("hash(%u) = %d\n", hashkey, bucketno);
#endif
MemoryContextSwitchTo(oldContext);