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 1r4n9e-00AEGD-Pi for pgsql-bugs@arkaria.postgresql.org; Sun, 19 Nov 2023 19:08:26 +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 1r4n9c-004VbB-7X for pgsql-bugs@arkaria.postgresql.org; Sun, 19 Nov 2023 19:08:24 +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 1r4n9b-004Vaz-VH for pgsql-bugs@lists.postgresql.org; Sun, 19 Nov 2023 19:08:23 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1r4n9V-007Hxz-Bh for pgsql-bugs@lists.postgresql.org; Sun, 19 Nov 2023 19:08:23 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 3AJJ85rD1130865; Sun, 19 Nov 2023 14:08:06 -0500 From: Tom Lane To: dmigowski@ikoffice.de cc: pgsql-bugs@lists.postgresql.org, Andres Freund Subject: Re: BUG #18205: Performance regression with NOT NULL checks. In-reply-to: <18205-53c59cab45881d52@postgresql.org> References: <18205-53c59cab45881d52@postgresql.org> Comments: In-reply-to PG Bug reporting form message dated "Sun, 19 Nov 2023 15:26:32 +0000" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1130863.1700420885.1@sss.pgh.pa.us> Content-Transfer-Encoding: quoted-printable Date: Sun, 19 Nov 2023 14:08:05 -0500 Message-ID: <1130864.1700420885@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk PG Bug reporting form writes: > I found out that selecting from a wide table with a single not-null wher= e > clause leads to severe performance regression when upgrading from Postgr= eSQL > 9.5 to PostgreSQL 15. I spent some time poking into this. "git bisect" pins the blame on commit b8d7f053c5c2bf2a7e8734fe3327f6a8bc711755 Author: Andres Freund Date: Tue Mar 14 15:45:36 2017 -0700 Faster expression evaluation and targetlist projection. The time needed for the seqscan gets about 50% worse at that commit (on my test machine, anyway): -> Seq Scan on testtable t (cost=3D0.00..51892.80 rows=3D9730 width=3D= 4) (actual time=3D0.010..204.937 rows=3D6000000 loops=3D1) Filter: (y IS NULL) versus -> Seq Scan on testtable t (cost=3D0.00..51892.80 rows=3D9730 width=3D= 4) (actual time=3D0.013..317.069 rows=3D6000000 loops=3D1) Filter: (y IS NULL) "perf" says that the extra time is mostly spent in slot_deform_tuple's inner loop: for (; attnum < natts; attnum++) { Form_pg_attribute thisatt =3D att[attnum]; if (hasnulls && att_isnull(attnum, bp)) { values[attnum] =3D (Datum) 0; isnull[attnum] =3D true; slow =3D true; /* can't use attcacheoff anymore */ continue; } ... which confused me, because that code doesn't look materially different in v10 than 9.6. I eventually realized that the reason is that we reach slot_deform_tuple with natts =3D 26 in the new code, but in the old code we do not, thanks to this short-circuit in slot_getattr: /* * check if target attribute is null: no point in groveling through tu= ple */ if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits)) { *isnull =3D true; return (Datum) 0; } So that results in not having to deconstruct most of the tuple, whereas in the new code we do have to, thanks to b8d7f053c's decision to batch all the variable-value-extraction work. This is a pretty narrow corner case: it would only matter if the column you're testing for null-ness is far past any other column the query needs to fetch. So I'm not sure that it's worth doing anything about. You could imagine special processing for NullTest-on-a-simple-Var: exclude the Var from the ones that we extract normally and instead compile it into some sort of "is column k NULL" test on the HeapTuple. But that seems messy, and it could be a significant pessimization for storage methods that aren't like heapam. On the whole I'm inclined to say "sorry, that's the price of progress". But it is a bit sad that a patch intended to be a performance win shows a loss this big on a (presumably) real-world case. regards, tom lane