aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execTuples.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-11-25 04:24:48 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-11-25 04:24:48 +0000
commitdab52ab13d3d3cce26e9bcc3193eb285c195d430 (patch)
treed7b4ebc7af6d4e09341637179e46d212c69070af /src/backend/executor/execTuples.c
parentc0a2f8cc4decba933f0ebb6d5b4ffd9eca036a78 (diff)
downloadpostgresql-dab52ab13d3d3cce26e9bcc3193eb285c195d430.tar.gz
postgresql-dab52ab13d3d3cce26e9bcc3193eb285c195d430.zip
Improve ExecStoreTuple to be smarter about replacing the contents of
a TupleTableSlot: instead of calling ExecClearTuple, inline the needed operations, so that we can avoid redundant steps. In particular, when the old and new tuples are both on the same disk page, avoid releasing and re-acquiring the buffer pin --- this saves work in both the bufmgr and ResourceOwner modules. To make this improvement actually useful, partially revert a change I made on 2004-04-21 that caused SeqNext et al to call ExecClearTuple before ExecStoreTuple. The motivation for that, to avoid grabbing the BufMgrLock separately for releasing the old buffer and grabbing the new one, no longer applies. My profiling says that this saves about 5% of the CPU time for an all-in-memory seqscan.
Diffstat (limited to 'src/backend/executor/execTuples.c')
-rw-r--r--src/backend/executor/execTuples.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 7a4f11f5d9f..09c7dd55f50 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.89 2005/11/22 18:17:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.90 2005/11/25 04:24:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -402,28 +402,38 @@ ExecStoreTuple(HeapTuple tuple,
Assert(BufferIsValid(buffer) ? (!shouldFree) : true);
/*
- * clear out any old contents of the slot
+ * Free any old physical tuple belonging to the slot.
*/
- if (!slot->tts_isempty)
- ExecClearTuple(slot);
+ if (slot->tts_shouldFree)
+ heap_freetuple(slot->tts_tuple);
/*
- * store the new tuple into the specified slot.
+ * Store the new tuple into the specified slot.
*/
slot->tts_isempty = false;
slot->tts_shouldFree = shouldFree;
slot->tts_tuple = tuple;
+ /* Mark extracted state invalid */
+ slot->tts_nvalid = 0;
+
/*
* If tuple is on a disk page, keep the page pinned as long as we hold a
* pointer into it. We assume the caller already has such a pin.
+ *
+ * This is coded to optimize the case where the slot previously held a
+ * tuple on the same disk page: in that case releasing and re-acquiring
+ * the pin is a waste of cycles. This is a common situation during
+ * seqscans, so it's worth troubling over.
*/
- slot->tts_buffer = buffer;
- if (BufferIsValid(buffer))
- IncrBufferRefCount(buffer);
-
- /* Mark extracted state invalid */
- slot->tts_nvalid = 0;
+ if (slot->tts_buffer != buffer)
+ {
+ if (BufferIsValid(slot->tts_buffer))
+ ReleaseBuffer(slot->tts_buffer);
+ slot->tts_buffer = buffer;
+ if (BufferIsValid(buffer))
+ IncrBufferRefCount(buffer);
+ }
return slot;
}