From 4c119fbcd49ba882791c7b99a1e934b985468e9f Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Wed, 11 Oct 2017 16:49:31 -0700 Subject: Improve performance of SendRowDescriptionMessage. There's three categories of changes leading to better performance: - Splitting the per-attribute part of SendRowDescriptionMessage into a v2 and a v3 version allows avoiding branches for every attribute. - Preallocating the size of the buffer to be big enough for all attributes and then using pq_write* avoids unnecessary buffer size checks & resizing. - Reusing a persistently allocated StringInfo for all SendRowDescriptionMessage() invocations avoids repeated allocations & reallocations. Author: Andres Freund Discussion: https://postgr.es/m/20170914063418.sckdzgjfrsbekae4@alap3.anarazel.de --- src/backend/tcop/postgres.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'src/backend/tcop/postgres.c') diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index edea6f177bb..338ce81331d 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -165,6 +165,10 @@ static bool RecoveryConflictPending = false; static bool RecoveryConflictRetryable = true; static ProcSignalReason RecoveryConflictReason; +/* reused buffer to pass to SendRowDescriptionMessage() */ +static MemoryContext row_description_context = NULL; +static StringInfoData row_description_buf; + /* ---------------------------------------------------------------- * decls for routines only used in this file * ---------------------------------------------------------------- @@ -2315,7 +2319,6 @@ static void exec_describe_statement_message(const char *stmt_name) { CachedPlanSource *psrc; - StringInfoData buf; int i; /* @@ -2371,16 +2374,17 @@ exec_describe_statement_message(const char *stmt_name) /* * First describe the parameters... */ - pq_beginmessage(&buf, 't'); /* parameter description message type */ - pq_sendint(&buf, psrc->num_params, 2); + pq_beginmessage_reuse(&row_description_buf, 't'); /* parameter description + * message type */ + pq_sendint(&row_description_buf, psrc->num_params, 2); for (i = 0; i < psrc->num_params; i++) { Oid ptype = psrc->param_types[i]; - pq_sendint(&buf, (int) ptype, 4); + pq_sendint(&row_description_buf, (int) ptype, 4); } - pq_endmessage(&buf); + pq_endmessage_reuse(&row_description_buf); /* * Next send RowDescription or NoData to describe the result... @@ -2392,7 +2396,10 @@ exec_describe_statement_message(const char *stmt_name) /* Get the plan's primary targetlist */ tlist = CachedPlanGetTargetList(psrc, NULL); - SendRowDescriptionMessage(psrc->resultDesc, tlist, NULL); + SendRowDescriptionMessage(&row_description_buf, + psrc->resultDesc, + tlist, + NULL); } else pq_putemptymessage('n'); /* NoData */ @@ -2444,7 +2451,8 @@ exec_describe_portal_message(const char *portal_name) return; /* can't actually do anything... */ if (portal->tupDesc) - SendRowDescriptionMessage(portal->tupDesc, + SendRowDescriptionMessage(&row_description_buf, + portal->tupDesc, FetchPortalTargetList(portal), portal->formats); else @@ -3830,6 +3838,19 @@ PostgresMain(int argc, char *argv[], "MessageContext", ALLOCSET_DEFAULT_SIZES); + /* + * Create memory context and buffer used for RowDescription messages. As + * SendRowDescriptionMessage(), via exec_describe_statement_message(), is + * frequently executed for ever single statement, we don't want to + * allocate a separate buffer every time. + */ + row_description_context = AllocSetContextCreate(TopMemoryContext, + "RowDescriptionContext", + ALLOCSET_DEFAULT_SIZES); + MemoryContextSwitchTo(row_description_context); + initStringInfo(&row_description_buf); + MemoryContextSwitchTo(TopMemoryContext); + /* * Remember stand-alone backend startup time */ -- cgit v1.2.3