diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 606c920b06..2735945c6c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -150,6 +150,7 @@ typedef struct PartitionDispatchData PartitionDesc partdesc; TupleTableSlot *tupslot; AttrMap *tupmap; + ResultRelInfo *lastPartInfo; int indexes[FLEXIBLE_ARRAY_MEMBER]; } PartitionDispatchData; @@ -291,6 +292,35 @@ ExecFindPartition(ModifyTableState *mtstate, CHECK_FOR_INTERRUPTS(); + /* + * Check if the saved partition accepts this tuple by evaluating its + * partition constraint against the tuple. If it does, we save a trip + * to get_partition_for_tuple(), which can be a slightly more expensive + * way to get the same partition, especially if there are many + * partitions to search through. + */ + if (dispatch->lastPartInfo) + { + TupleTableSlot *tmpslot; + TupleConversionMap *map; + + rri = dispatch->lastPartInfo; + map = rri->ri_RootToPartitionMap; + if (map) + tmpslot = execute_attr_map_slot(map->attrMap, rootslot, + rri->ri_PartitionTupleSlot); + else + tmpslot = rootslot; + if (ExecPartitionCheck(rri, tmpslot, estate, false)) + { + /* and restore ecxt's scantuple */ + ecxt->ecxt_scantuple = ecxt_scantuple_saved; + MemoryContextSwitchTo(oldcxt); + return rri; + } + dispatch->lastPartInfo = rri = NULL; + } + rel = dispatch->reldesc; partdesc = dispatch->partdesc; @@ -372,6 +402,19 @@ ExecFindPartition(ModifyTableState *mtstate, } Assert(rri != NULL); + /* + * Remember this partition for the next tuple inserted into this + * parent; see at the top of this loop how it's decided whether + * the next tuple can indeed reuse this partition. + * + * Do this only if we have range/list partitions, because only + * in that case it's conceivable that consecutively inserted rows + * tend to go into the same partition. + */ + if ((dispatch->key->strategy == PARTITION_STRATEGY_RANGE || + dispatch->key->strategy == PARTITION_STRATEGY_RANGE)) + dispatch->lastPartInfo = rri; + /* Signal to terminate the loop */ dispatch = NULL; } @@ -1051,6 +1094,8 @@ ExecInitPartitionDispatchInfo(EState *estate, pd->tupslot = NULL; } + pd->lastPartInfo = NULL; + /* * Initialize with -1 to signify that the corresponding partition's * ResultRelInfo or PartitionDispatch has not been created yet.