mirror of https://github.com/postgres/postgres
Avoid copying index tuples when building an index.
The previous code, perhaps out of concern for avoid memory leaks, formed the tuple in one memory context and then copied it to another memory context. However, this doesn't appear to be necessary, since index_form_tuple and the functions it calls take precautions against leaking memory. In my testing, building the tuple directly inside the sort context shaves several percent off the index build time. Rearrange things so we do that. Patch by me. Review by Amit Kapila, Tom Lane, Andres Freund.
This commit is contained in:
parent
03a25cec8d
commit
9f03ca9151
|
@ -28,6 +28,9 @@
|
|||
|
||||
/* ----------------
|
||||
* index_form_tuple
|
||||
*
|
||||
* This shouldn't leak any memory; otherwise, callers such as
|
||||
* tuplesort_putindextuplevalues() will be very unhappy.
|
||||
* ----------------
|
||||
*/
|
||||
IndexTuple
|
||||
|
|
|
@ -142,26 +142,23 @@ hashbuildCallback(Relation index,
|
|||
HashBuildState *buildstate = (HashBuildState *) state;
|
||||
IndexTuple itup;
|
||||
|
||||
/* form an index tuple and point it at the heap tuple */
|
||||
itup = _hash_form_tuple(index, values, isnull);
|
||||
itup->t_tid = htup->t_self;
|
||||
|
||||
/* Hash indexes don't index nulls, see notes in hashinsert */
|
||||
if (IndexTupleHasNulls(itup))
|
||||
{
|
||||
pfree(itup);
|
||||
if (isnull[0])
|
||||
return;
|
||||
}
|
||||
|
||||
/* Either spool the tuple for sorting, or just put it into the index */
|
||||
if (buildstate->spool)
|
||||
_h_spool(itup, buildstate->spool);
|
||||
_h_spool(buildstate->spool, &htup->t_self, values, isnull);
|
||||
else
|
||||
{
|
||||
/* form an index tuple and point it at the heap tuple */
|
||||
itup = _hash_form_tuple(index, values, isnull);
|
||||
itup->t_tid = htup->t_self;
|
||||
_hash_doinsert(index, itup);
|
||||
pfree(itup);
|
||||
}
|
||||
|
||||
buildstate->indtuples += 1;
|
||||
|
||||
pfree(itup);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -184,10 +181,6 @@ hashinsert(PG_FUNCTION_ARGS)
|
|||
#endif
|
||||
IndexTuple itup;
|
||||
|
||||
/* generate an index tuple */
|
||||
itup = _hash_form_tuple(rel, values, isnull);
|
||||
itup->t_tid = *ht_ctid;
|
||||
|
||||
/*
|
||||
* If the single index key is null, we don't insert it into the index.
|
||||
* Hash tables support scans on '='. Relational algebra says that A = B
|
||||
|
@ -197,11 +190,12 @@ hashinsert(PG_FUNCTION_ARGS)
|
|||
* NOTNULL scans, but that's an artifact of the strategy map architecture
|
||||
* chosen in 1986, not of the way nulls are handled here.
|
||||
*/
|
||||
if (IndexTupleHasNulls(itup))
|
||||
{
|
||||
pfree(itup);
|
||||
if (isnull[0])
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
/* generate an index tuple */
|
||||
itup = _hash_form_tuple(rel, values, isnull);
|
||||
itup->t_tid = *ht_ctid;
|
||||
|
||||
_hash_doinsert(rel, itup);
|
||||
|
||||
|
|
|
@ -90,9 +90,10 @@ _h_spooldestroy(HSpool *hspool)
|
|||
* spool an index entry into the sort file.
|
||||
*/
|
||||
void
|
||||
_h_spool(IndexTuple itup, HSpool *hspool)
|
||||
_h_spool(HSpool *hspool, ItemPointer self, Datum *values, bool *isnull)
|
||||
{
|
||||
tuplesort_putindextuple(hspool->sortstate, itup);
|
||||
tuplesort_putindextuplevalues(hspool->sortstate, hspool->index,
|
||||
self, values, isnull);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -171,28 +171,21 @@ btbuildCallback(Relation index,
|
|||
void *state)
|
||||
{
|
||||
BTBuildState *buildstate = (BTBuildState *) state;
|
||||
IndexTuple itup;
|
||||
|
||||
/* form an index tuple and point it at the heap tuple */
|
||||
itup = index_form_tuple(RelationGetDescr(index), values, isnull);
|
||||
itup->t_tid = htup->t_self;
|
||||
|
||||
/*
|
||||
* insert the index tuple into the appropriate spool file for subsequent
|
||||
* processing
|
||||
*/
|
||||
if (tupleIsAlive || buildstate->spool2 == NULL)
|
||||
_bt_spool(itup, buildstate->spool);
|
||||
_bt_spool(buildstate->spool, &htup->t_self, values, isnull);
|
||||
else
|
||||
{
|
||||
/* dead tuples are put into spool2 */
|
||||
buildstate->haveDead = true;
|
||||
_bt_spool(itup, buildstate->spool2);
|
||||
_bt_spool(buildstate->spool2, &htup->t_self, values, isnull);
|
||||
}
|
||||
|
||||
buildstate->indtuples += 1;
|
||||
|
||||
pfree(itup);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -185,9 +185,10 @@ _bt_spooldestroy(BTSpool *btspool)
|
|||
* spool an index entry into the sort file.
|
||||
*/
|
||||
void
|
||||
_bt_spool(IndexTuple itup, BTSpool *btspool)
|
||||
_bt_spool(BTSpool *btspool, ItemPointer self, Datum *values, bool *isnull)
|
||||
{
|
||||
tuplesort_putindextuple(btspool->sortstate, itup);
|
||||
tuplesort_putindextuplevalues(btspool->sortstate, btspool->index,
|
||||
self, values, isnull);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1134,22 +1134,25 @@ tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
|
|||
}
|
||||
|
||||
/*
|
||||
* Accept one index tuple while collecting input data for sort.
|
||||
*
|
||||
* Note that the input tuple is always copied; the caller need not save it.
|
||||
* Collect one index tuple while collecting input data for sort, building
|
||||
* it from caller-supplied values.
|
||||
*/
|
||||
void
|
||||
tuplesort_putindextuple(Tuplesortstate *state, IndexTuple tuple)
|
||||
tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
|
||||
ItemPointer self, Datum *values,
|
||||
bool *isnull)
|
||||
{
|
||||
MemoryContext oldcontext = MemoryContextSwitchTo(state->sortcontext);
|
||||
SortTuple stup;
|
||||
|
||||
/*
|
||||
* Copy the given tuple into memory we control, and decrease availMem.
|
||||
* Then call the common code.
|
||||
*/
|
||||
COPYTUP(state, &stup, (void *) tuple);
|
||||
|
||||
stup.tuple = index_form_tuple(RelationGetDescr(rel), values, isnull);
|
||||
((IndexTuple) stup.tuple)->t_tid = *self;
|
||||
USEMEM(state, GetMemoryChunkSpace(stup.tuple));
|
||||
/* set up first-column key value */
|
||||
stup.datum1 = index_getattr((IndexTuple) stup.tuple,
|
||||
1,
|
||||
RelationGetDescr(state->indexRel),
|
||||
&stup.isnull1);
|
||||
puttuple_common(state, &stup);
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
|
|
@ -336,7 +336,8 @@ typedef struct HSpool HSpool; /* opaque struct in hashsort.c */
|
|||
|
||||
extern HSpool *_h_spoolinit(Relation heap, Relation index, uint32 num_buckets);
|
||||
extern void _h_spooldestroy(HSpool *hspool);
|
||||
extern void _h_spool(IndexTuple itup, HSpool *hspool);
|
||||
extern void _h_spool(HSpool *hspool, ItemPointer self,
|
||||
Datum *values, bool *isnull);
|
||||
extern void _h_indexbuild(HSpool *hspool);
|
||||
|
||||
/* hashutil.c */
|
||||
|
|
|
@ -717,7 +717,8 @@ typedef struct BTSpool BTSpool; /* opaque type known only within nbtsort.c */
|
|||
extern BTSpool *_bt_spoolinit(Relation heap, Relation index,
|
||||
bool isunique, bool isdead);
|
||||
extern void _bt_spooldestroy(BTSpool *btspool);
|
||||
extern void _bt_spool(IndexTuple itup, BTSpool *btspool);
|
||||
extern void _bt_spool(BTSpool *btspool, ItemPointer self,
|
||||
Datum *values, bool *isnull);
|
||||
extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
|
||||
|
||||
/*
|
||||
|
|
|
@ -84,7 +84,9 @@ extern void tuplesort_set_bound(Tuplesortstate *state, int64 bound);
|
|||
extern void tuplesort_puttupleslot(Tuplesortstate *state,
|
||||
TupleTableSlot *slot);
|
||||
extern void tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup);
|
||||
extern void tuplesort_putindextuple(Tuplesortstate *state, IndexTuple tuple);
|
||||
extern void tuplesort_putindextuplevalues(Tuplesortstate *state,
|
||||
Relation rel, ItemPointer self,
|
||||
Datum *values, bool *isnull);
|
||||
extern void tuplesort_putdatum(Tuplesortstate *state, Datum val,
|
||||
bool isNull);
|
||||
|
||||
|
|
Loading…
Reference in New Issue