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, '}');