Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4c119fb

Browse files
committed
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
1 parent cff440d commit 4c119fb

File tree

3 files changed

+138
-47
lines changed

3 files changed

+138
-47
lines changed

src/backend/access/common/printtup.c

+108-38
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ static bool printtup_internal_20(TupleTableSlot *slot, DestReceiver *self);
3232
static void printtup_shutdown(DestReceiver *self);
3333
static void printtup_destroy(DestReceiver *self);
3434

35+
static void SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo,
36+
List *targetlist, int16 *formats);
37+
static void SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo,
38+
List *targetlist, int16 *formats);
3539

3640
/* ----------------------------------------------------------------
3741
* printtup / debugtup support
@@ -161,7 +165,8 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
161165
* descriptor of the tuples.
162166
*/
163167
if (myState->sendDescrip)
164-
SendRowDescriptionMessage(typeinfo,
168+
SendRowDescriptionMessage(&myState->buf,
169+
typeinfo,
165170
FetchPortalTargetList(portal),
166171
portal->formats);
167172

@@ -189,61 +194,126 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
189194
* send zeroes for the format codes in that case.
190195
*/
191196
void
192-
SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
197+
SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
198+
List *targetlist, int16 *formats)
193199
{
194200
int natts = typeinfo->natts;
195201
int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
202+
203+
/* tuple descriptor message type */
204+
pq_beginmessage_reuse(buf, 'T');
205+
/* # of attrs in tuples */
206+
pq_sendint16(buf, natts);
207+
208+
if (proto >= 3)
209+
SendRowDescriptionCols_3(buf, typeinfo, targetlist, formats);
210+
else
211+
SendRowDescriptionCols_2(buf, typeinfo, targetlist, formats);
212+
213+
pq_endmessage_reuse(buf);
214+
}
215+
216+
/*
217+
* Send description for each column when using v3+ protocol
218+
*/
219+
static void
220+
SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
221+
{
222+
int natts = typeinfo->natts;
196223
int i;
197-
StringInfoData buf;
198224
ListCell *tlist_item = list_head(targetlist);
199225

200-
pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
201-
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
226+
/*
227+
* Preallocate memory for the entire message to be sent. That allows to
228+
* use the significantly faster inline pqformat.h functions and to avoid
229+
* reallocations.
230+
*
231+
* Have to overestimate the size of the column-names, to account for
232+
* character set overhead.
233+
*/
234+
enlargeStringInfo(buf, (NAMEDATALEN * MAX_CONVERSION_GROWTH /* attname */
235+
+ sizeof(Oid) /* resorigtbl */
236+
+ sizeof(AttrNumber) /* resorigcol */
237+
+ sizeof(Oid) /* atttypid */
238+
+ sizeof(int16) /* attlen */
239+
+ sizeof(int32) /* attypmod */
240+
+ sizeof(int16) /* format */
241+
) * natts);
202242

203243
for (i = 0; i < natts; ++i)
204244
{
205245
Form_pg_attribute att = TupleDescAttr(typeinfo, i);
206246
Oid atttypid = att->atttypid;
207247
int32 atttypmod = att->atttypmod;
248+
Oid resorigtbl;
249+
AttrNumber resorigcol;
250+
int16 format;
251+
252+
/*
253+
* If column is a domain, send the base type and typmod instead.
254+
* Lookup before sending any ints, for efficiency.
255+
*/
256+
atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
208257

209-
pq_sendstring(&buf, NameStr(att->attname));
210-
/* column ID info appears in protocol 3.0 and up */
211-
if (proto >= 3)
258+
/* Do we have a non-resjunk tlist item? */
259+
while (tlist_item &&
260+
((TargetEntry *) lfirst(tlist_item))->resjunk)
261+
tlist_item = lnext(tlist_item);
262+
if (tlist_item)
212263
{
213-
/* Do we have a non-resjunk tlist item? */
214-
while (tlist_item &&
215-
((TargetEntry *) lfirst(tlist_item))->resjunk)
216-
tlist_item = lnext(tlist_item);
217-
if (tlist_item)
218-
{
219-
TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
220-
221-
pq_sendint(&buf, tle->resorigtbl, 4);
222-
pq_sendint(&buf, tle->resorigcol, 2);
223-
tlist_item = lnext(tlist_item);
224-
}
225-
else
226-
{
227-
/* No info available, so send zeroes */
228-
pq_sendint(&buf, 0, 4);
229-
pq_sendint(&buf, 0, 2);
230-
}
264+
TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
265+
266+
resorigtbl = tle->resorigtbl;
267+
resorigcol = tle->resorigcol;
268+
tlist_item = lnext(tlist_item);
231269
}
232-
/* If column is a domain, send the base type and typmod instead */
233-
atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
234-
pq_sendint(&buf, (int) atttypid, sizeof(atttypid));
235-
pq_sendint(&buf, att->attlen, sizeof(att->attlen));
236-
pq_sendint(&buf, atttypmod, sizeof(atttypmod));
237-
/* format info appears in protocol 3.0 and up */
238-
if (proto >= 3)
270+
else
239271
{
240-
if (formats)
241-
pq_sendint(&buf, formats[i], 2);
242-
else
243-
pq_sendint(&buf, 0, 2);
272+
/* No info available, so send zeroes */
273+
resorigtbl = 0;
274+
resorigcol = 0;
244275
}
276+
277+
if (formats)
278+
format = formats[i];
279+
else
280+
format = 0;
281+
282+
pq_writestring(buf, NameStr(att->attname));
283+
pq_writeint32(buf, resorigtbl);
284+
pq_writeint16(buf, resorigcol);
285+
pq_writeint32(buf, atttypid);
286+
pq_writeint16(buf, att->attlen);
287+
pq_writeint32(buf, atttypmod);
288+
pq_writeint16(buf, format);
289+
}
290+
}
291+
292+
/*
293+
* Send description for each column when using v2 protocol
294+
*/
295+
static void
296+
SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
297+
{
298+
int natts = typeinfo->natts;
299+
int i;
300+
301+
for (i = 0; i < natts; ++i)
302+
{
303+
Form_pg_attribute att = TupleDescAttr(typeinfo, i);
304+
Oid atttypid = att->atttypid;
305+
int32 atttypmod = att->atttypmod;
306+
307+
/* If column is a domain, send the base type and typmod instead */
308+
atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
309+
310+
pq_sendstring(buf, NameStr(att->attname));
311+
/* column ID only info appears in protocol 3.0 and up */
312+
pq_sendint32(buf, atttypid);
313+
pq_sendint16(buf, att->attlen);
314+
pq_sendint32(buf, atttypmod);
315+
/* format info only appears in protocol 3.0 and up */
245316
}
246-
pq_endmessage(&buf);
247317
}
248318

249319
/*

src/backend/tcop/postgres.c

+28-7
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ static bool RecoveryConflictPending = false;
165165
static bool RecoveryConflictRetryable = true;
166166
static ProcSignalReason RecoveryConflictReason;
167167

168+
/* reused buffer to pass to SendRowDescriptionMessage() */
169+
static MemoryContext row_description_context = NULL;
170+
static StringInfoData row_description_buf;
171+
168172
/* ----------------------------------------------------------------
169173
* decls for routines only used in this file
170174
* ----------------------------------------------------------------
@@ -2315,7 +2319,6 @@ static void
23152319
exec_describe_statement_message(const char *stmt_name)
23162320
{
23172321
CachedPlanSource *psrc;
2318-
StringInfoData buf;
23192322
int i;
23202323

23212324
/*
@@ -2371,16 +2374,17 @@ exec_describe_statement_message(const char *stmt_name)
23712374
/*
23722375
* First describe the parameters...
23732376
*/
2374-
pq_beginmessage(&buf, 't'); /* parameter description message type */
2375-
pq_sendint(&buf, psrc->num_params, 2);
2377+
pq_beginmessage_reuse(&row_description_buf, 't'); /* parameter description
2378+
* message type */
2379+
pq_sendint(&row_description_buf, psrc->num_params, 2);
23762380

23772381
for (i = 0; i < psrc->num_params; i++)
23782382
{
23792383
Oid ptype = psrc->param_types[i];
23802384

2381-
pq_sendint(&buf, (int) ptype, 4);
2385+
pq_sendint(&row_description_buf, (int) ptype, 4);
23822386
}
2383-
pq_endmessage(&buf);
2387+
pq_endmessage_reuse(&row_description_buf);
23842388

23852389
/*
23862390
* Next send RowDescription or NoData to describe the result...
@@ -2392,7 +2396,10 @@ exec_describe_statement_message(const char *stmt_name)
23922396
/* Get the plan's primary targetlist */
23932397
tlist = CachedPlanGetTargetList(psrc, NULL);
23942398

2395-
SendRowDescriptionMessage(psrc->resultDesc, tlist, NULL);
2399+
SendRowDescriptionMessage(&row_description_buf,
2400+
psrc->resultDesc,
2401+
tlist,
2402+
NULL);
23962403
}
23972404
else
23982405
pq_putemptymessage('n'); /* NoData */
@@ -2444,7 +2451,8 @@ exec_describe_portal_message(const char *portal_name)
24442451
return; /* can't actually do anything... */
24452452

24462453
if (portal->tupDesc)
2447-
SendRowDescriptionMessage(portal->tupDesc,
2454+
SendRowDescriptionMessage(&row_description_buf,
2455+
portal->tupDesc,
24482456
FetchPortalTargetList(portal),
24492457
portal->formats);
24502458
else
@@ -3830,6 +3838,19 @@ PostgresMain(int argc, char *argv[],
38303838
"MessageContext",
38313839
ALLOCSET_DEFAULT_SIZES);
38323840

3841+
/*
3842+
* Create memory context and buffer used for RowDescription messages. As
3843+
* SendRowDescriptionMessage(), via exec_describe_statement_message(), is
3844+
* frequently executed for ever single statement, we don't want to
3845+
* allocate a separate buffer every time.
3846+
*/
3847+
row_description_context = AllocSetContextCreate(TopMemoryContext,
3848+
"RowDescriptionContext",
3849+
ALLOCSET_DEFAULT_SIZES);
3850+
MemoryContextSwitchTo(row_description_context);
3851+
initStringInfo(&row_description_buf);
3852+
MemoryContextSwitchTo(TopMemoryContext);
3853+
38333854
/*
38343855
* Remember stand-alone backend startup time
38353856
*/

src/include/access/printtup.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ extern DestReceiver *printtup_create_DR(CommandDest dest);
2020

2121
extern void SetRemoteDestReceiverParams(DestReceiver *self, Portal portal);
2222

23-
extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist,
24-
int16 *formats);
23+
extern void SendRowDescriptionMessage(StringInfo buf,
24+
TupleDesc typeinfo, List *targetlist, int16 *formats);
2525

2626
extern void debugStartup(DestReceiver *self, int operation,
2727
TupleDesc typeinfo);

0 commit comments

Comments
 (0)