From 71d668ee94571693283e2be1a57bf43400fc7ace Mon Sep 17 00:00:00 2001
From: Hou Zhijie <houzj.fnst@cn.fujitsu.com>
Date: Thu, 25 Jul 2024 15:36:47 +0800
Subject: [PATCH v1 1/2] avoid duplicate table scan for cross partition update

When performing a cross-partition update action in apply worker, it
accidentally scans the old partition twice, resulting in noticeable overhead.
This commit optimizes it by removing the redundant table scan.
---
 src/backend/replication/logical/worker.c | 27 ++++++++++++++----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index ec96b5fe85..9a61679130 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -2991,6 +2991,7 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
 				ResultRelInfo *partrelinfo_new;
 				Relation	partrel_new;
 				bool		found;
+				EPQState	epqstate;
 
 				/* Get the matching local tuple from the partition. */
 				found = FindReplTupleInLocalRel(edata, partrel,
@@ -3021,6 +3022,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
 								 newtup);
 				MemoryContextSwitchTo(oldctx);
 
+				EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1, NIL);
+				ExecOpenIndices(partrelinfo, false);
+
 				/*
 				 * Does the updated tuple still satisfy the current
 				 * partition's constraint?
@@ -3036,18 +3040,11 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
 					 * work already done above to find the local tuple in the
 					 * partition.
 					 */
-					EPQState	epqstate;
-
-					EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1, NIL);
-					ExecOpenIndices(partrelinfo, false);
-
 					EvalPlanQualSetSlot(&epqstate, remoteslot_part);
 					TargetPrivilegesCheck(partrelinfo->ri_RelationDesc,
 										  ACL_UPDATE);
 					ExecSimpleRelationUpdate(partrelinfo, estate, &epqstate,
 											 localslot, remoteslot_part);
-					ExecCloseIndices(partrelinfo);
-					EvalPlanQualEnd(&epqstate);
 				}
 				else
 				{
@@ -3090,10 +3087,15 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
 											 get_namespace_name(RelationGetNamespace(partrel_new)),
 											 RelationGetRelationName(partrel_new));
 
-					/* DELETE old tuple found in the old partition. */
-					apply_handle_delete_internal(edata, partrelinfo,
-												 localslot,
-												 part_entry->localindexoid);
+					/*
+					 * Simply DELETE old tuple found in the old partition. We
+					 * don't call apply_handle_delete_internal() here to avoid
+					 * repeating some work already done above to find the
+					 * local tuple in the partition.
+					 */
+					EvalPlanQualSetSlot(&epqstate, localslot);
+					TargetPrivilegesCheck(partrelinfo->ri_RelationDesc, ACL_DELETE);
+					ExecSimpleRelationDelete(partrelinfo, estate, &epqstate, localslot);
 
 					/* INSERT new tuple into the new partition. */
 
@@ -3123,6 +3125,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
 					apply_handle_insert_internal(edata, partrelinfo_new,
 												 remoteslot_part);
 				}
+
+				ExecCloseIndices(partrelinfo);
+				EvalPlanQualEnd(&epqstate);
 			}
 			break;
 
-- 
2.31.1

