Skip to content

Commit 8f2ea8b

Browse files
committed
Resurrect heap_deformtuple(), this time implemented as a singly nested
loop over the fields instead of a loop around heap_getattr. This is considerably faster (O(N) instead of O(N^2)) when there are nulls or varlena fields, since those prevent use of attcacheoff. Replace loops over heap_getattr with heap_deformtuple in situations where all or most of the fields have to be fetched, such as printtup and tuptoaster. Profiling done more than a year ago shows that this should be a nice win for situations involving many-column tables.
1 parent af44cac commit 8f2ea8b

File tree

8 files changed

+314
-208
lines changed

8 files changed

+314
-208
lines changed

src/backend/access/common/heaptuple.c

Lines changed: 166 additions & 114 deletions
Large diffs are not rendered by default.

src/backend/access/common/printtup.c

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.81 2004/05/26 04:41:03 neilc Exp $
12+
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.82 2004/06/04 20:35:21 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -65,6 +65,8 @@ typedef struct
6565
TupleDesc attrinfo; /* The attr info we are set up for */
6666
int nattrs;
6767
PrinttupAttrInfo *myinfo; /* Cached info about each attr */
68+
Datum *values; /* preallocated space for deformtuple */
69+
char *nulls;
6870
} DR_printtup;
6971

7072
/* ----------------
@@ -103,6 +105,8 @@ printtup_create_DR(CommandDest dest, Portal portal)
103105
self->attrinfo = NULL;
104106
self->nattrs = 0;
105107
self->myinfo = NULL;
108+
self->values = NULL;
109+
self->nulls = NULL;
106110

107111
return (DestReceiver *) self;
108112
}
@@ -243,15 +247,27 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
243247
int16 *formats = myState->portal->formats;
244248
int i;
245249

250+
/* get rid of any old data */
246251
if (myState->myinfo)
247-
pfree(myState->myinfo); /* get rid of any old data */
252+
pfree(myState->myinfo);
248253
myState->myinfo = NULL;
254+
if (myState->values)
255+
pfree(myState->values);
256+
myState->values = NULL;
257+
if (myState->nulls)
258+
pfree(myState->nulls);
259+
myState->nulls = NULL;
260+
249261
myState->attrinfo = typeinfo;
250262
myState->nattrs = numAttrs;
251263
if (numAttrs <= 0)
252264
return;
265+
253266
myState->myinfo = (PrinttupAttrInfo *)
254267
palloc0(numAttrs * sizeof(PrinttupAttrInfo));
268+
myState->values = (Datum *) palloc(numAttrs * sizeof(Datum));
269+
myState->nulls = (char *) palloc(numAttrs * sizeof(char));
270+
255271
for (i = 0; i < numAttrs; i++)
256272
{
257273
PrinttupAttrInfo *thisState = myState->myinfo + i;
@@ -297,6 +313,11 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
297313
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
298314
printtup_prepare_info(myState, typeinfo, natts);
299315

316+
/*
317+
* deconstruct the tuple (faster than a heap_getattr loop)
318+
*/
319+
heap_deformtuple(tuple, typeinfo, myState->values, myState->nulls);
320+
300321
/*
301322
* Prepare a DataRow message
302323
*/
@@ -310,12 +331,10 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
310331
for (i = 0; i < natts; ++i)
311332
{
312333
PrinttupAttrInfo *thisState = myState->myinfo + i;
313-
Datum origattr,
334+
Datum origattr = myState->values[i],
314335
attr;
315-
bool isnull;
316336

317-
origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
318-
if (isnull)
337+
if (myState->nulls[i] == 'n')
319338
{
320339
pq_sendint(&buf, -1, 4);
321340
continue;
@@ -383,6 +402,11 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
383402
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
384403
printtup_prepare_info(myState, typeinfo, natts);
385404

405+
/*
406+
* deconstruct the tuple (faster than a heap_getattr loop)
407+
*/
408+
heap_deformtuple(tuple, typeinfo, myState->values, myState->nulls);
409+
386410
/*
387411
* tell the frontend to expect new tuple data (in ASCII style)
388412
*/
@@ -395,7 +419,7 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
395419
k = 1 << 7;
396420
for (i = 0; i < natts; ++i)
397421
{
398-
if (!heap_attisnull(tuple, i + 1))
422+
if (myState->nulls[i] != 'n')
399423
j |= k; /* set bit if not null */
400424
k >>= 1;
401425
if (k == 0) /* end of byte? */
@@ -414,13 +438,11 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
414438
for (i = 0; i < natts; ++i)
415439
{
416440
PrinttupAttrInfo *thisState = myState->myinfo + i;
417-
Datum origattr,
441+
Datum origattr = myState->values[i],
418442
attr;
419-
bool isnull;
420443
char *outputstr;
421444

422-
origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
423-
if (isnull)
445+
if (myState->nulls[i] == 'n')
424446
continue;
425447

426448
Assert(thisState->format == 0);
@@ -461,6 +483,13 @@ printtup_shutdown(DestReceiver *self)
461483
if (myState->myinfo)
462484
pfree(myState->myinfo);
463485
myState->myinfo = NULL;
486+
if (myState->values)
487+
pfree(myState->values);
488+
myState->values = NULL;
489+
if (myState->nulls)
490+
pfree(myState->nulls);
491+
myState->nulls = NULL;
492+
464493
myState->attrinfo = NULL;
465494
}
466495

@@ -587,6 +616,11 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
587616
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
588617
printtup_prepare_info(myState, typeinfo, natts);
589618

619+
/*
620+
* deconstruct the tuple (faster than a heap_getattr loop)
621+
*/
622+
heap_deformtuple(tuple, typeinfo, myState->values, myState->nulls);
623+
590624
/*
591625
* tell the frontend to expect new tuple data (in binary style)
592626
*/
@@ -599,7 +633,7 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
599633
k = 1 << 7;
600634
for (i = 0; i < natts; ++i)
601635
{
602-
if (!heap_attisnull(tuple, i + 1))
636+
if (myState->nulls[i] != 'n')
603637
j |= k; /* set bit if not null */
604638
k >>= 1;
605639
if (k == 0) /* end of byte? */
@@ -618,13 +652,11 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
618652
for (i = 0; i < natts; ++i)
619653
{
620654
PrinttupAttrInfo *thisState = myState->myinfo + i;
621-
Datum origattr,
655+
Datum origattr = myState->values[i],
622656
attr;
623-
bool isnull;
624657
bytea *outputbytes;
625658

626-
origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
627-
if (isnull)
659+
if (myState->nulls[i] == 'n')
628660
continue;
629661

630662
Assert(thisState->format == 1);

src/backend/access/heap/tuptoaster.c

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.41 2003/11/29 19:51:40 pgsql Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.42 2004/06/04 20:35:21 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -281,15 +281,26 @@ toast_delete(Relation rel, HeapTuple oldtup)
281281
Form_pg_attribute *att;
282282
int numAttrs;
283283
int i;
284-
Datum value;
285-
bool isnull;
284+
Datum toast_values[MaxHeapAttributeNumber];
285+
char toast_nulls[MaxHeapAttributeNumber];
286286

287287
/*
288-
* Get the tuple descriptor, the number of and attribute descriptors.
288+
* Get the tuple descriptor and break down the tuple into fields.
289+
*
290+
* NOTE: it's debatable whether to use heap_deformtuple() here or
291+
* just heap_getattr() only the varlena columns. The latter could
292+
* win if there are few varlena columns and many non-varlena ones.
293+
* However, heap_deformtuple costs only O(N) while the heap_getattr
294+
* way would cost O(N^2) if there are many varlena columns, so it
295+
* seems better to err on the side of linear cost. (We won't even
296+
* be here unless there's at least one varlena column, by the way.)
289297
*/
290298
tupleDesc = rel->rd_att;
291-
numAttrs = tupleDesc->natts;
292299
att = tupleDesc->attrs;
300+
numAttrs = tupleDesc->natts;
301+
302+
Assert(numAttrs <= MaxHeapAttributeNumber);
303+
heap_deformtuple(oldtup, tupleDesc, toast_values, toast_nulls);
293304

294305
/*
295306
* Check for external stored attributes and delete them from the
@@ -299,8 +310,9 @@ toast_delete(Relation rel, HeapTuple oldtup)
299310
{
300311
if (att[i]->attlen == -1)
301312
{
302-
value = heap_getattr(oldtup, i + 1, tupleDesc, &isnull);
303-
if (!isnull && VARATT_IS_EXTERNAL(value))
313+
Datum value = toast_values[i];
314+
315+
if (toast_nulls[i] != 'n' && VARATT_IS_EXTERNAL(value))
304316
toast_delete_datum(rel, value);
305317
}
306318
}
@@ -321,8 +333,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
321333
Form_pg_attribute *att;
322334
int numAttrs;
323335
int i;
324-
bool old_isnull;
325-
bool new_isnull;
326336

327337
bool need_change = false;
328338
bool need_free = false;
@@ -333,18 +343,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
333343

334344
char toast_action[MaxHeapAttributeNumber];
335345
char toast_nulls[MaxHeapAttributeNumber];
346+
char toast_oldnulls[MaxHeapAttributeNumber];
336347
Datum toast_values[MaxHeapAttributeNumber];
348+
Datum toast_oldvalues[MaxHeapAttributeNumber];
337349
int32 toast_sizes[MaxHeapAttributeNumber];
338350
bool toast_free[MaxHeapAttributeNumber];
339351
bool toast_delold[MaxHeapAttributeNumber];
340352

341353
/*
342-
* Get the tuple descriptor, the number of and attribute descriptors
343-
* and the location of the tuple values.
354+
* Get the tuple descriptor and break down the tuple(s) into fields.
344355
*/
345356
tupleDesc = rel->rd_att;
346-
numAttrs = tupleDesc->natts;
347357
att = tupleDesc->attrs;
358+
numAttrs = tupleDesc->natts;
359+
360+
Assert(numAttrs <= MaxHeapAttributeNumber);
361+
heap_deformtuple(newtup, tupleDesc, toast_values, toast_nulls);
362+
if (oldtup != NULL)
363+
heap_deformtuple(oldtup, tupleDesc, toast_oldvalues, toast_oldnulls);
348364

349365
/* ----------
350366
* Then collect information about the values given
@@ -353,12 +369,15 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
353369
* ' ' default handling
354370
* 'p' already processed --- don't touch it
355371
* 'x' incompressible, but OK to move off
372+
*
373+
* NOTE: toast_sizes[i] is only made valid for varlena attributes with
374+
* toast_action[i] different from 'p'.
356375
* ----------
357376
*/
358377
memset(toast_action, ' ', numAttrs * sizeof(char));
359-
memset(toast_nulls, ' ', numAttrs * sizeof(char));
360378
memset(toast_free, 0, numAttrs * sizeof(bool));
361379
memset(toast_delold, 0, numAttrs * sizeof(bool));
380+
362381
for (i = 0; i < numAttrs; i++)
363382
{
364383
varattrib *old_value;
@@ -369,27 +388,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
369388
/*
370389
* For UPDATE get the old and new values of this attribute
371390
*/
372-
old_value = (varattrib *) DatumGetPointer(
373-
heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));
374-
toast_values[i] =
375-
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
391+
old_value = (varattrib *) DatumGetPointer(toast_oldvalues[i]);
376392
new_value = (varattrib *) DatumGetPointer(toast_values[i]);
377393

378394
/*
379395
* If the old value is an external stored one, check if it has
380396
* changed so we have to delete it later.
381397
*/
382-
if (!old_isnull && att[i]->attlen == -1 &&
398+
if (att[i]->attlen == -1 && toast_oldnulls[i] != 'n' &&
383399
VARATT_IS_EXTERNAL(old_value))
384400
{
385-
if (new_isnull || !VARATT_IS_EXTERNAL(new_value) ||
401+
if (toast_nulls[i] == 'n' || !VARATT_IS_EXTERNAL(new_value) ||
386402
old_value->va_content.va_external.va_valueid !=
387403
new_value->va_content.va_external.va_valueid ||
388404
old_value->va_content.va_external.va_toastrelid !=
389405
new_value->va_content.va_external.va_toastrelid)
390406
{
391407
/*
392-
* The old external store value isn't needed any more
408+
* The old external stored value isn't needed any more
393409
* after the update
394410
*/
395411
toast_delold[i] = true;
@@ -413,23 +429,21 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
413429
/*
414430
* For INSERT simply get the new value
415431
*/
416-
toast_values[i] =
417-
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
432+
new_value = (varattrib *) DatumGetPointer(toast_values[i]);
418433
}
419434

420435
/*
421436
* Handle NULL attributes
422437
*/
423-
if (new_isnull)
438+
if (toast_nulls[i] == 'n')
424439
{
425440
toast_action[i] = 'p';
426-
toast_nulls[i] = 'n';
427441
has_nulls = true;
428442
continue;
429443
}
430444

431445
/*
432-
* Now look at varsize attributes
446+
* Now look at varlena attributes
433447
*/
434448
if (att[i]->attlen == -1)
435449
{
@@ -461,10 +475,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
461475
else
462476
{
463477
/*
464-
* Not a variable size attribute, plain storage always
478+
* Not a varlena attribute, plain storage always
465479
*/
466480
toast_action[i] = 'p';
467-
toast_sizes[i] = att[i]->attlen;
468481
}
469482
}
470483

@@ -768,8 +781,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
768781
if (need_delold)
769782
for (i = 0; i < numAttrs; i++)
770783
if (toast_delold[i])
771-
toast_delete_datum(rel,
772-
heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));
784+
toast_delete_datum(rel, toast_oldvalues[i]);
773785
}
774786

775787

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy