Hi,

In https://postgr.es/m/20190201162404.onngi77f26baem4g%40alap3.anarazel.de
I noticed that composite_to_json() deforms column-by-column. Given that
it always processes all columns, that seems quite the waste of resources.

In some quick'n dirty dirty testing this gives a ~4% benefit in a table
without nulls and varlenas, and ~7% in one with both. I assume that if
one were to test with a bit wider table the win would be bigger.

A short test shows that it'd be slower to allocate nulls/values with
palloc rather than using MaxHeapAttributeNumber. Given that only output
functions are called from within composite_to_json(), I think that's ok.

Greetings,

Andres Freund
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index de0d0723b71..8724022df54 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -1755,6 +1755,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
 	int			i;
 	bool		needsep = false;
 	const char *sep;
+	Datum		values[MaxHeapAttributeNumber];
+	bool		nulls[MaxHeapAttributeNumber];
 
 	sep = use_line_feeds ? ",\n " : ",";
 
@@ -1772,10 +1774,10 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
 
 	appendStringInfoChar(result, '{');
 
+	heap_deform_tuple(tuple, tupdesc, values, nulls);
+
 	for (i = 0; i < tupdesc->natts; i++)
 	{
-		Datum		val;
-		bool		isnull;
 		char	   *attname;
 		JsonTypeCategory tcategory;
 		Oid			outfuncoid;
@@ -1792,9 +1794,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
 		escape_json(result, attname);
 		appendStringInfoChar(result, ':');
 
-		val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
-
-		if (isnull)
+		if (nulls[i])
 		{
 			tcategory = JSONTYPE_NULL;
 			outfuncoid = InvalidOid;
@@ -1802,7 +1802,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
 		else
 			json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
 
-		datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
+		datum_to_json(values[i], nulls[i], result, tcategory, outfuncoid,
+					  false);
 	}
 
 	appendStringInfoChar(result, '}');

Reply via email to