Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1vGZc4-0017Fl-I7 for pgsql-hackers@arkaria.postgresql.org; Wed, 05 Nov 2025 09:15:32 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1vGZc3-001PQL-IQ for pgsql-hackers@arkaria.postgresql.org; Wed, 05 Nov 2025 09:15:30 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1vGZc3-001PQB-7M for pgsql-hackers@lists.postgresql.org; Wed, 05 Nov 2025 09:15:30 +0000 Received: from mail-pf1-x430.google.com ([2607:f8b0:4864:20::430]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vGZbz-0065Zm-2F for pgsql-hackers@lists.postgresql.org; Wed, 05 Nov 2025 09:15:29 +0000 Received: by mail-pf1-x430.google.com with SMTP id d2e1a72fcca58-782e93932ffso6178300b3a.3 for ; Wed, 05 Nov 2025 01:15:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1762334125; x=1762938925; darn=lists.postgresql.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=LIX+55pKpmsbp4qfB0c+zun5GVWhll50Ay6MN9vU0nw=; b=mw7b5Nld714PImif4p7OS7nBsa0wLiHzg/yaAAo2uiK/OckkX4Y/spjPOYhNcZgUrL 4S9QBWZrhi1OMagAgljN/2twvt2je55Al9BN9Hc86LBp2FVLG9n0eWLrYCzJKbhusYia s2RgX8F7zVs1jMt8mxu/BUBPQKtcBkWvUSiaY2cPJlT1pq2UbM4IxiThPOY/VWGHAfdm Q+dp49eLrdntNSGl34uWzAPKm8r3i6gfklqp7JYQS/Uh7z6VpiyqE2reZxIpcVfHWa2a I+gcPOn6oc/EOG55Vltl38gYWLxBzvCbehvdxuyi9X/dKixvKPOt3zscA/cU6/Qrh85H mV2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762334125; x=1762938925; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LIX+55pKpmsbp4qfB0c+zun5GVWhll50Ay6MN9vU0nw=; b=okFZU0obF/dYiINOYVmu8neTzcNnlNKu1vQBeu0yw8lMVaF7FLbSToX7eq/7ybOrBW KjcKbgfcaBYXDk/ysZ2WyImt6NzhnAtl7rSPgxFvBl0Yu0oM4kPCY5x8fQRM1wP8tt3a b5SP8VB3hL68AdxJpB3CHPeHIkoD7pJXJmcuLqnNlZCRmsnUE5Vyh4ZBwgBim268+NIp wQCTW1qFoZHgwe0hgtVvpiYEJlDvJO8V4yczfZ/VrVdCtkgA31A7KbdxW7zckjmJTs34 Y++T1luQX4iXhjYhcLV39WhnWcbReiDc2nGBnN0aWDUMqj6by3q2ZXHK9tNK6XIrxN98 wjZA== X-Forwarded-Encrypted: i=1; AJvYcCUBRnJsJI8h2qiQkhjDdO3vO4+JjIQJxGxfrs6Ry1H6Vs+v2vBUJc2W/9VzibnuE7IqH9rvglBozpf1sQtx@lists.postgresql.org X-Gm-Message-State: AOJu0YxQgzxDrpHDddnNyl0KavMdn/fVnJWs/LXGl7EEJRQfbs9IEzdw IcZBPADdm8lCkpFtzD0OJ6AnKockwjXMWmU4ysb+MG+5lOb2emX/bYmo X-Gm-Gg: ASbGncugQBEwVHSDpZZGmBqfm9EEZcvX7jbm0YO5Sfnm4o6WUygScpUnhSyuON9BdhU vb6YTx3wIqxhpkcOb9MPq2YUezmDX8kr3WxBAObmzu+DOLpWk/a4/JJqO1ZhAINCtntjwQ8zodP ktlCIuX2TK1L15Lry6k1/hI9WRZ2S0AZBeiECtKjLW0d8DquKNtjpe7LvGqRAI7TnmB4K/n6dnz qyZXW9MDZe6tKgduiqbbwzi/8AJkwOE1d/irsxrOoYcEMH7cJcRX1EBThMaNZ46WfV+2ZN/dmjj RV2n3qLNiu544B7PFbVJOP9ddHH209kw3jKlN0aJrq63huLViwLfDQWi3X/le+JQkk3WxjTv3sp W9sK9knNP9fvi+ZBim/dejJm1ij98TC/JPmP1YDyU+tJ/kgVbKryef0V02bM16wQqlXZ59ah+lr FN9JFWa+pyhRM= X-Google-Smtp-Source: AGHT+IGMXMW3Xmvo2Pr7EL5rTC1VlZ/b35cGjQQz2fGBoL/HUFmtN0Gwi77HNn8bGrDSFDM9lD3HPA== X-Received: by 2002:a05:6a20:3d1e:b0:343:ad1:d569 with SMTP id adf61e73a8af0-34f84018df0mr3205744637.6.1762334125157; Wed, 05 Nov 2025 01:15:25 -0800 (PST) Received: from smtpclient.apple ([170.178.170.211]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-ba1f86b0688sm4903626a12.28.2025.11.05.01.15.22 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 05 Nov 2025 01:15:24 -0800 (PST) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81\)) Subject: Re: Making jsonb_agg() faster From: Chao Li In-Reply-To: <354608.1762195230@sss.pgh.pa.us> Date: Wed, 5 Nov 2025 17:14:40 +0800 Cc: jian he , pgsql-hackers@lists.postgresql.org Content-Transfer-Encoding: quoted-printable Message-Id: <8A521EB7-2716-4E01-8505-98755B78D8EF@gmail.com> References: <1060917.1753202222@sss.pgh.pa.us> <617666.1755277022@sss.pgh.pa.us> <654628.1755297629@sss.pgh.pa.us> <2129790.1755889894@sss.pgh.pa.us> <68A1061C-81A5-46AA-AFA9-48294908254C@gmail.com> <2613D418-67E0-4DD8-BDA6-AB1BB04DB1A2@gmail.com> <2466173.1756498180@sss.pgh.pa.us> <163563.1762117009@sss.pgh.pa.us> <354608.1762195230@sss.pgh.pa.us> To: Tom Lane X-Mailer: Apple Mail (2.3826.700.81) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk > On Nov 4, 2025, at 02:40, Tom Lane wrote: >=20 > Chao Li writes: >>> On Nov 3, 2025, at 04:56, Tom Lane wrote: >>> PFA v3, rebased over 8a27d418f, no substantive changes whatever. >=20 >> I am on vacation this week, I only find a hour in the evening and did = an eyeball review without actually tracing and testing this patch set. >=20 > Thanks for looking at it! >=20 >> In elsewhere of the patch, you all use =E2=80=9CJsonbInState ps =3D = {0}=E2=80=9D to do the initialization, only this place uses memset(). = Can we keep consistent and use {0} here also. I see there is a = =E2=80=9Ccontinue=E2=80=9D and a =E2=80=9Cbreak=E2=80=9D before the = memset(), maybe you want to avoid unnecessary initialization. I guess = that is a tiny saving, but if you think that saving is worthwhile, I=E2=80= =99m fine with keeping the current code. >=20 > I intentionally made the 0001 patch as mechanical as possible, > and in particular did not second-guess existing decisions about > whether to initialize a variable in the declaration or later. > So I'm not excited about doing it differently in this one place. > There are some other memsets in the same area that could also > be replaced by "=3D {0}" if we cared to, but that seems like > material for a separate cleanup patch. >=20 >> Instead of hard-coding 12, can we use "sizeof(TimeTzADT)=E2=80=9D for = better readability? >=20 > No, because that's not the same :-(. sizeof() would produce 16, > on most machines anyway, thanks to alignment. But 12 is the > type's size according to pg_type. >=20 >> You left two =E2=80=9Cugly hack=E2=80=9D comments. Maybe add a short = description for why they are hack and what can be improved in the = future. >=20 > It's the same ugly hack as before, I just formatted the code more > legibly ... I didn't stop to look at whether there's a better way to > do it. Again, that seems like material for a different patch. >=20 > regards, tom lane I got some time today, so I ran some performance tests, which show me a = significant performance improvement from this patch. To run the test, I disabled asserts and built with -O2. The tests ran on = a MacBook M4. To prepare for some data: ``` DROP TABLE IF EXISTS jtest; CREATE TABLE jtest AS SELECT g AS id, (g % 1000) AS grp, g AS ival, = (g::text || '_str') AS sval, now() + (g || ' seconds')::interval AS = tsval FROM generate_series(1, 5_000_000) g; VACUUM ANALYZE jtest; ``` Then I ran the following tests against both master and a patched branch: 1. Jsonb_agg Patched: ``` evantest=3D# SELECT grp, jsonb_agg(jsonb_build_object('id', id, 'ival', = ival, 'sval', sval, 'tsval', tsval)) FROM jtest GROUP BY grp; Time: 5810.921 ms (00:05.811) evantest=3D# SELECT grp, jsonb_agg(jsonb_build_object('id', id, 'ival', = ival, 'sval', sval, 'tsval', tsval)) FROM jtest GROUP BY grp; Time: 5904.465 ms (00:05.904) evantest=3D# SELECT grp, jsonb_agg(jsonb_build_object('id', id, 'ival', = ival, 'sval', sval, 'tsval', tsval)) FROM jtest GROUP BY grp; Time: 5857.314 ms (00:05.857) ``` Master: ``` evantest=3D# SELECT grp, jsonb_agg(jsonb_build_object('id', id, 'ival', = ival, 'sval', sval, 'tsval', tsval)) FROM jtest GROUP BY grp; Time: 7310.648 ms (00:07.311) evantest=3D# SELECT grp, jsonb_agg(jsonb_build_object('id', id, 'ival', = ival, 'sval', sval, 'tsval', tsval)) FROM jtest GROUP BY grp; Time: 7333.428 ms (00:07.333) evantest=3D# SELECT grp, jsonb_agg(jsonb_build_object('id', id, 'ival', = ival, 'sval', sval, 'tsval', tsval)) FROM jtest GROUP BY grp; Time: 7257.666 ms (00:07.258) ``` Roughly 20% improvement. 2. Jsonb_object_agg Patched: ``` evantest=3D# SELECT jsonb_object_agg(id, sval) FROM jtest; Time: 767.258 ms evantest=3D# SELECT jsonb_object_agg(id, sval) FROM jtest; Time: 760.665 ms evantest=3D# SELECT jsonb_object_agg(id, sval) FROM jtest; Time: 772.326 ms ``` Master: ``` evantest=3D# SELECT jsonb_object_agg(id, sval) FROM jtest; Time: 1298.433 ms (00:01.298) evantest=3D# SELECT jsonb_object_agg(id, sval) FROM jtest; Time: 1286.029 ms (00:01.286) evantest=3D# SELECT jsonb_object_agg(id, sval) FROM jtest; Time: 1283.624 ms (00:01.284) ``` Roughly 40% improvement. 3. To_jsonb Patched: ``` evantest=3D# SELECT to_jsonb(ival), to_jsonb(sval), to_jsonb(tsval) FROM = jtest; Time: 2270.958 ms (00:02.271) evantest=3D# SELECT to_jsonb(ival), to_jsonb(sval), to_jsonb(tsval) FROM = jtest; Time: 2313.483 ms (00:02.313) evantest=3D# SELECT to_jsonb(ival), to_jsonb(sval), to_jsonb(tsval) FROM = jtest; Time: 2298.716 ms (00:02.299) ``` Master: ``` evantest=3D# SELECT to_jsonb(ival), to_jsonb(sval), to_jsonb(tsval) FROM = jtest; Time: 2490.771 ms (00:02.491) evantest=3D# SELECT to_jsonb(ival), to_jsonb(sval), to_jsonb(tsval) FROM = jtest; Time: 2514.326 ms (00:02.514) evantest=3D# SELECT to_jsonb(ival), to_jsonb(sval), to_jsonb(tsval) FROM = jtest; Time: 2509.924 ms (00:02.510) ``` Roughly 8% improvement. So, overall, this patch has done a great performance improvement. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/