Avoid duplicate table scans for cross-partition updates during logical replication.
authorAmit Kapila <akapila@postgresql.org>
Thu, 1 Aug 2024 04:41:06 +0000 (10:11 +0530)
committerAmit Kapila <akapila@postgresql.org>
Thu, 1 Aug 2024 04:41:06 +0000 (10:11 +0530)
When performing a cross-partition update in the apply worker, it
needlessly scans the old partition twice, resulting in noticeable
overhead.

This commit optimizes it by removing the redundant table scan.

Author: Hou Zhijie
Reviewed-by: Hayato Kuroda, Amit Kapila
Discussion: https://postgr.es/m/OS0PR01MB571623E39984D94CBB5341D994AB2@OS0PR01MB5716.jpnprd01.prod.outlook.com

src/backend/replication/logical/worker.c

index ec96b5fe85e6d44173327142cd831745cb7884af..6dc54c72838794d36f6b05473aec66242f680210 100644 (file)
@@ -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
                                {
@@ -3091,9 +3088,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
                                                                                         RelationGetRelationName(partrel_new));
 
                                        /* DELETE old tuple found in the old partition. */
-                                       apply_handle_delete_internal(edata, partrelinfo,
-                                                                                                localslot,
-                                                                                                part_entry->localindexoid);
+                                       EvalPlanQualSetSlot(&epqstate, localslot);
+                                       TargetPrivilegesCheck(partrelinfo->ri_RelationDesc, ACL_DELETE);
+                                       ExecSimpleRelationDelete(partrelinfo, estate, &epqstate, localslot);
 
                                        /* INSERT new tuple into the new partition. */
 
@@ -3123,6 +3120,9 @@ apply_handle_tuple_routing(ApplyExecutionData *edata,
                                        apply_handle_insert_internal(edata, partrelinfo_new,
                                                                                                 remoteslot_part);
                                }
+
+                               ExecCloseIndices(partrelinfo);
+                               EvalPlanQualEnd(&epqstate);
                        }
                        break;