mirror of https://github.com/postgres/postgres
Reset, not recreate, execGrouping.c style hashtables.
This uses the facility added in the preceding commit to fix
performance issues caused by rebuilding the hashtable (with its
comparator expression being the most expensive bit), after every
reset. That's especially important when the comparator is JIT
compiled.
Bug: #15592 #15486
Reported-By: Jakub Janeček, Dmitry Marakasov
Author: Andres Freund
Discussion:
https://postgr.es/m/15486-05850f065da42931@postgresql.org
https://postgr.es/m/20190114180423.ywhdg2iagzvh43we@alap3.anarazel.de
Backpatch: 11, where I broke this in bf6c614a2f
This commit is contained in:
parent
317ffdfeaa
commit
356687bd82
|
@ -1246,7 +1246,7 @@ find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
|
|||
}
|
||||
|
||||
/*
|
||||
* Initialize the hash table(s) to empty.
|
||||
* (Re-)initialize the hash table(s) to empty.
|
||||
*
|
||||
* To implement hashed aggregation, we need a hashtable that stores a
|
||||
* representative tuple and an array of AggStatePerGroup structs for each
|
||||
|
@ -1257,9 +1257,9 @@ find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
|
|||
* We have a separate hashtable and associated perhash data structure for each
|
||||
* grouping set for which we're doing hashing.
|
||||
*
|
||||
* The hash tables always live in the hashcontext's per-tuple memory context
|
||||
* (there is only one of these for all tables together, since they are all
|
||||
* reset at the same time).
|
||||
* The contents of the hash tables always live in the hashcontext's per-tuple
|
||||
* memory context (there is only one of these for all tables together, since
|
||||
* they are all reset at the same time).
|
||||
*/
|
||||
static void
|
||||
build_hash_table(AggState *aggstate)
|
||||
|
@ -1278,17 +1278,21 @@ build_hash_table(AggState *aggstate)
|
|||
|
||||
Assert(perhash->aggnode->numGroups > 0);
|
||||
|
||||
perhash->hashtable = BuildTupleHashTable(&aggstate->ss.ps,
|
||||
perhash->hashslot->tts_tupleDescriptor,
|
||||
perhash->numCols,
|
||||
perhash->hashGrpColIdxHash,
|
||||
perhash->eqfuncoids,
|
||||
perhash->hashfunctions,
|
||||
perhash->aggnode->numGroups,
|
||||
additionalsize,
|
||||
aggstate->hashcontext->ecxt_per_tuple_memory,
|
||||
tmpmem,
|
||||
DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
|
||||
if (perhash->hashtable)
|
||||
ResetTupleHashTable(perhash->hashtable);
|
||||
else
|
||||
perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
|
||||
perhash->hashslot->tts_tupleDescriptor,
|
||||
perhash->numCols,
|
||||
perhash->hashGrpColIdxHash,
|
||||
perhash->eqfuncoids,
|
||||
perhash->hashfunctions,
|
||||
perhash->aggnode->numGroups,
|
||||
additionalsize,
|
||||
aggstate->ss.ps.state->es_query_cxt,
|
||||
aggstate->hashcontext->ecxt_per_tuple_memory,
|
||||
tmpmem,
|
||||
DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,17 +37,18 @@ build_hash_table(RecursiveUnionState *rustate)
|
|||
Assert(node->numCols > 0);
|
||||
Assert(node->numGroups > 0);
|
||||
|
||||
rustate->hashtable = BuildTupleHashTable(&rustate->ps,
|
||||
desc,
|
||||
node->numCols,
|
||||
node->dupColIdx,
|
||||
rustate->eqfuncoids,
|
||||
rustate->hashfunctions,
|
||||
node->numGroups,
|
||||
0,
|
||||
rustate->tableContext,
|
||||
rustate->tempContext,
|
||||
false);
|
||||
rustate->hashtable = BuildTupleHashTableExt(&rustate->ps,
|
||||
desc,
|
||||
node->numCols,
|
||||
node->dupColIdx,
|
||||
rustate->eqfuncoids,
|
||||
rustate->hashfunctions,
|
||||
node->numGroups,
|
||||
0,
|
||||
rustate->ps.state->es_query_cxt,
|
||||
rustate->tableContext,
|
||||
rustate->tempContext,
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -317,9 +318,9 @@ ExecReScanRecursiveUnion(RecursiveUnionState *node)
|
|||
if (node->tableContext)
|
||||
MemoryContextResetAndDeleteChildren(node->tableContext);
|
||||
|
||||
/* And rebuild empty hashtable if needed */
|
||||
/* Empty hashtable if needed */
|
||||
if (plan->numCols > 0)
|
||||
build_hash_table(node);
|
||||
ResetTupleHashTable(node->hashtable);
|
||||
|
||||
/* reset processing state */
|
||||
node->recursing = false;
|
||||
|
|
|
@ -126,17 +126,18 @@ build_hash_table(SetOpState *setopstate)
|
|||
Assert(node->strategy == SETOP_HASHED);
|
||||
Assert(node->numGroups > 0);
|
||||
|
||||
setopstate->hashtable = BuildTupleHashTable(&setopstate->ps,
|
||||
desc,
|
||||
node->numCols,
|
||||
node->dupColIdx,
|
||||
setopstate->eqfuncoids,
|
||||
setopstate->hashfunctions,
|
||||
node->numGroups,
|
||||
0,
|
||||
setopstate->tableContext,
|
||||
econtext->ecxt_per_tuple_memory,
|
||||
false);
|
||||
setopstate->hashtable = BuildTupleHashTableExt(&setopstate->ps,
|
||||
desc,
|
||||
node->numCols,
|
||||
node->dupColIdx,
|
||||
setopstate->eqfuncoids,
|
||||
setopstate->hashfunctions,
|
||||
node->numGroups,
|
||||
0,
|
||||
setopstate->ps.state->es_query_cxt,
|
||||
setopstate->tableContext,
|
||||
econtext->ecxt_per_tuple_memory,
|
||||
false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -635,7 +636,7 @@ ExecReScanSetOp(SetOpState *node)
|
|||
/* And rebuild empty hashtable if needed */
|
||||
if (((SetOp *) node->ps.plan)->strategy == SETOP_HASHED)
|
||||
{
|
||||
build_hash_table(node);
|
||||
ResetTupleHashTable(node->hashtable);
|
||||
node->table_filled = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -481,8 +481,8 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
|
|||
Assert(subplan->subLinkType == ANY_SUBLINK);
|
||||
|
||||
/*
|
||||
* If we already had any hash tables, destroy 'em; then create empty hash
|
||||
* table(s).
|
||||
* If we already had any hash tables, reset 'em; otherwise create empty
|
||||
* hash table(s).
|
||||
*
|
||||
* If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
|
||||
* NULL) results of the IN operation, then we have to store subplan output
|
||||
|
@ -505,17 +505,21 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
|
|||
if (nbuckets < 1)
|
||||
nbuckets = 1;
|
||||
|
||||
node->hashtable = BuildTupleHashTable(node->parent,
|
||||
node->descRight,
|
||||
ncols,
|
||||
node->keyColIdx,
|
||||
node->tab_eq_funcoids,
|
||||
node->tab_hash_funcs,
|
||||
nbuckets,
|
||||
0,
|
||||
node->hashtablecxt,
|
||||
node->hashtempcxt,
|
||||
false);
|
||||
if (node->hashtable)
|
||||
ResetTupleHashTable(node->hashtable);
|
||||
else
|
||||
node->hashtable = BuildTupleHashTableExt(node->parent,
|
||||
node->descRight,
|
||||
ncols,
|
||||
node->keyColIdx,
|
||||
node->tab_eq_funcoids,
|
||||
node->tab_hash_funcs,
|
||||
nbuckets,
|
||||
0,
|
||||
node->planstate->state->es_query_cxt,
|
||||
node->hashtablecxt,
|
||||
node->hashtempcxt,
|
||||
false);
|
||||
|
||||
if (!subplan->unknownEqFalse)
|
||||
{
|
||||
|
@ -527,17 +531,22 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
|
|||
if (nbuckets < 1)
|
||||
nbuckets = 1;
|
||||
}
|
||||
node->hashnulls = BuildTupleHashTable(node->parent,
|
||||
node->descRight,
|
||||
ncols,
|
||||
node->keyColIdx,
|
||||
node->tab_eq_funcoids,
|
||||
node->tab_hash_funcs,
|
||||
nbuckets,
|
||||
0,
|
||||
node->hashtablecxt,
|
||||
node->hashtempcxt,
|
||||
false);
|
||||
|
||||
if (node->hashnulls)
|
||||
ResetTupleHashTable(node->hashtable);
|
||||
else
|
||||
node->hashnulls = BuildTupleHashTableExt(node->parent,
|
||||
node->descRight,
|
||||
ncols,
|
||||
node->keyColIdx,
|
||||
node->tab_eq_funcoids,
|
||||
node->tab_hash_funcs,
|
||||
nbuckets,
|
||||
0,
|
||||
node->planstate->state->es_query_cxt,
|
||||
node->hashtablecxt,
|
||||
node->hashtempcxt,
|
||||
false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue