summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorTom Lane2017-09-07 23:41:51 +0000
committerTom Lane2017-09-07 23:41:51 +0000
commit3ca930fc39ccf987c1c22fd04a1e7463b5dd0dfd (patch)
treef7f73a2b2c9fd2c9cdb95860e0e89adba2c253ba /src/include
parentb976499480bdbab6d69a11e47991febe53865adc (diff)
Improve performance of get_actual_variable_range with recently-dead tuples.
In commit fccebe421, we hacked get_actual_variable_range() to scan the index with SnapshotDirty, so that if there are many uncommitted tuples at the end of the index range, it wouldn't laboriously scan through all of them looking for a live value to return. However, that didn't fix it for the case of many recently-dead tuples at the end of the index; SnapshotDirty recognizes those as committed dead and so we're back to the same problem. To improve the situation, invent a "SnapshotNonVacuumable" snapshot type and use that instead. The reason this helps is that, if the snapshot rejects a given index entry, we know that the indexscan will mark that index entry as killed. This means the next get_actual_variable_range() scan will proceed past that entry without visiting the heap, making the scan a lot faster. We may end up accepting a recently-dead tuple as being the estimated extremal value, but that doesn't seem much worse than the compromise we made before to accept not-yet-committed extremal values. The cost of the scan is still proportional to the number of dead index entries at the end of the range, so in the interval after a mass delete but before VACUUM's cleaned up the mess, it's still possible for get_actual_variable_range() to take a noticeable amount of time, if you've got enough such dead entries. But the constant factor is much much better than before, since all we need to do with each index entry is test its "killed" bit. We chose to back-patch commit fccebe421 at the time, but I'm hesitant to do so here, because this form of the problem seems to affect many fewer people. Also, even when it happens, it's less bad than the case fixed by commit fccebe421 because we don't get the contention effects from expensive TransactionIdIsInProgress tests. Dmitriy Sarafannikov, reviewed by Andrey Borodin Discussion: https://postgr.es/m/[email protected]
Diffstat (limited to 'src/include')
-rw-r--r--src/include/utils/snapshot.h4
-rw-r--r--src/include/utils/tqual.h10
2 files changed, 13 insertions, 1 deletions
diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h
index 074cc818649..bf519778df4 100644
--- a/src/include/utils/snapshot.h
+++ b/src/include/utils/snapshot.h
@@ -41,6 +41,7 @@ typedef bool (*SnapshotSatisfiesFunc) (HeapTuple htup,
* * MVCC snapshots taken during recovery (in Hot-Standby mode)
* * Historic MVCC snapshots used during logical decoding
* * snapshots passed to HeapTupleSatisfiesDirty()
+ * * snapshots passed to HeapTupleSatisfiesNonVacuumable()
* * snapshots used for SatisfiesAny, Toast, Self where no members are
* accessed.
*
@@ -56,7 +57,8 @@ typedef struct SnapshotData
/*
* The remaining fields are used only for MVCC snapshots, and are normally
* just zeroes in special snapshots. (But xmin and xmax are used
- * specially by HeapTupleSatisfiesDirty.)
+ * specially by HeapTupleSatisfiesDirty, and xmin is used specially by
+ * HeapTupleSatisfiesNonVacuumable.)
*
* An MVCC snapshot can never see the effects of XIDs >= xmax. It can see
* the effects of all older XIDs except those listed in the snapshot. xmin
diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h
index 036d9898d69..9a3b56e5f03 100644
--- a/src/include/utils/tqual.h
+++ b/src/include/utils/tqual.h
@@ -66,6 +66,8 @@ extern bool HeapTupleSatisfiesToast(HeapTuple htup,
Snapshot snapshot, Buffer buffer);
extern bool HeapTupleSatisfiesDirty(HeapTuple htup,
Snapshot snapshot, Buffer buffer);
+extern bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup,
+ Snapshot snapshot, Buffer buffer);
extern bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup,
Snapshot snapshot, Buffer buffer);
@@ -101,6 +103,14 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data,
((snapshotdata).satisfies = HeapTupleSatisfiesDirty)
/*
+ * Similarly, some initialization is required for a NonVacuumable snapshot.
+ * The caller must supply the xmin horizon to use (e.g., RecentGlobalXmin).
+ */
+#define InitNonVacuumableSnapshot(snapshotdata, xmin_horizon) \
+ ((snapshotdata).satisfies = HeapTupleSatisfiesNonVacuumable, \
+ (snapshotdata).xmin = (xmin_horizon))
+
+/*
* Similarly, some initialization is required for SnapshotToast. We need
* to set lsn and whenTaken correctly to support snapshot_too_old.
*/