v2-0001-Limit-batch_size-for-foreign-insert-with-work_mem.patch
text/x-diff
Filename: v2-0001-Limit-batch_size-for-foreign-insert-with-work_mem.patch
Type: text/x-diff
Part: 0
From 7efc88ffb4d90e935ca1e17ac3d4c753a2de4ef0 Mon Sep 17 00:00:00 2001
From: Alexander Pyhalov <a.pyhalov@postgrespro.ru>
Date: Tue, 16 Dec 2025 18:46:27 +0300
Subject: [PATCH 1/3] Limit batch_size for foreign insert with work_mem
Option batch_size can be set on foreign server level. It can be very optimistic
even for one table with different tuple lengths. To prevent large memory usage
limit effective batch size with work_mem.
---
src/backend/executor/nodeModifyTable.c | 15 ++++++++++++---
src/include/nodes/execnodes.h | 1 +
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 874b71e6608..a28beca63ff 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -943,12 +943,18 @@ ExecInsert(ModifyTableContext *context,
if (resultRelInfo->ri_BatchSize > 1)
{
bool flushed = false;
+ Size tuple_len;
+
+ /* Compute length of the current tuple */
+ slot_getallattrs(slot);
+ tuple_len = heap_compute_data_size(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull);
/*
- * When we've reached the desired batch size, perform the
- * insertion.
+ * When we've reached the desired batch size or exceeded work_mem,
+ * perform the insertion.
*/
- if (resultRelInfo->ri_NumSlots == resultRelInfo->ri_BatchSize)
+ if (resultRelInfo->ri_NumSlots == resultRelInfo->ri_BatchSize ||
+ ((tuple_len + resultRelInfo->ri_BatchMemoryUsed > work_mem * 1024) && (resultRelInfo->ri_NumSlots > 0)))
{
ExecBatchInsert(mtstate, resultRelInfo,
resultRelInfo->ri_Slots,
@@ -1019,6 +1025,8 @@ ExecInsert(ModifyTableContext *context,
resultRelInfo));
resultRelInfo->ri_NumSlots++;
+ /* Batch size can grow up to tuple length even if it exceeds work_mem. */
+ resultRelInfo->ri_BatchMemoryUsed += tuple_len;
MemoryContextSwitchTo(oldContext);
@@ -1418,6 +1426,7 @@ ExecBatchInsert(ModifyTableState *mtstate,
ExecClearTuple(planSlots[i]);
}
resultRelInfo->ri_NumSlots = 0;
+ resultRelInfo->ri_BatchMemoryUsed = 0;
}
/*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 3968429f991..b82ec938228 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -542,6 +542,7 @@ typedef struct ResultRelInfo
int ri_NumSlots; /* number of slots in the array */
int ri_NumSlotsInitialized; /* number of initialized slots */
int ri_BatchSize; /* max slots inserted in a single batch */
+ int ri_BatchMemoryUsed; /* memory used by batch */
TupleTableSlot **ri_Slots; /* input tuples for batch insert */
TupleTableSlot **ri_PlanSlots;
--
2.43.0