1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-29 10:41:53 +03:00

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
This commit is contained in:
Andres Freund
2017-10-11 16:49:31 -07:00
parent cff440d368
commit 4c119fbcd4
3 changed files with 140 additions and 49 deletions

View File

@ -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
*/