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.96) (envelope-from ) id 1wmTre-000o7g-2l for pgsql-bugs@arkaria.postgresql.org; Wed, 22 Jul 2026 10:07:47 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wmTrd-00BUZ9-1t for pgsql-bugs@arkaria.postgresql.org; Wed, 22 Jul 2026 10:07:45 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wmRTw-00ArfL-1i for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:35:08 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wmRTt-00000001Ny5-1Mkj for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:35:07 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=0URviBglySGaLq/r1xPstLjEqQy3NHc6DLrv2of61ag=; b=t0aIK8YJcRZM8OCLEYkl0+Fvr5 kxcoe6h/KidmfQAOzhfZ7Oa4byUZnFkqE+qpw7HUlwxnAeQKMOXz7duBHqMJ4Fx+Ws0nGLE5AvbDY y5vsIgrAxOQp87Apy6JZMyOYEI1rqqWziZO4a8riGpcCIw4dUMw0gUS/YOtXzDC0FNknQHe0p40p+ XVbGWRzcMt3zY9jC3lOx0IVYntwWPBO/w6yI44bxnXQ+WE4pN3fE5MrQa83UQnHVMmvVbtYlp3Tg9 X5AgecDF2KTv6miBECHWsjNX6AXvywDL55y8BpIXSH47OvvS39afntTESB/Cp9ZAbx2jn8YVPOJuJ YkaNzgxw==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wmRTs-001ldz-2n for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:35:05 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1wmRTr-000000027cI-3MyS for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:35:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19572: Redundant predicate changes JIT decision and causes an 18x performance difference To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: 2320415112@qq.com Reply-To: 2320415112@qq.com, pgsql-bugs@lists.postgresql.org Date: Wed, 22 Jul 2026 07:34:28 +0000 Message-ID: <19572-f770e89412629023@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19572 Logged by: cl hl Email address: 2320415112@qq.com PostgreSQL version: 17.10 Operating system: Linux LAPTOP-2SQAVLB0 6.6.87.2-microsoft-standard- Description: =20 ## Description This issue concerns a predicate that already applies to one side of an inner join and is redundantly copied into the join condition. The transformation is semantics-preserving. PostgreSQL retains both copies and treats their selectivities as independent, even though they are identical. The underestimated row count lowers the total plan cost enough to change whether expensive JIT inlining and optimization are enabled. ### Expected Behaviour PostgreSQL should recognize identical predicates or account for their complete correlation. Adding a redundant copy should not change cardinality estimates, cross a JIT threshold, or produce a large execution-time difference between equivalent queries. ### Actual Behaviour In pair 3868, the predicate `t14.c4 NOT BETWEEN 30 AND 46` is present in the subquery `WHERE` clause. The mutated query also copies it into the preceding inner join's `ON` condition while retaining the original copy. The recorded plans show: | Measurement | Original | Redundant predicate | |---|---:|---:| | Estimated `t14` rows | 658 | 432 | | Top-level estimated rows | 16,367,750 | 10,746,000 | | Top-level cost | 610,279.14 | 399,518.16 | | JIT inlining | enabled | disabled | | JIT optimization | enabled | disabled | | Median execution time | 742.033 ms | 40.223 ms | The equivalent query with the redundant predicate is approximately 18.45x faster. The original cost exceeds PostgreSQL's default `jit_inline_above_cost` and `jit_optimize_above_cost` value of 500,000, while the underestimated mutated plan falls below it. Both plans compile 137 JIT functions, but only the original performs costly inlining and optimization. ## How to repeat The following standalone case uses lower session-local thresholds so the same mechanism can be reproduced with small tables. It does not change global server configuration. ```sql DROP TABLE IF EXISTS redundant_join_fact; DROP TABLE IF EXISTS redundant_join_dimension; CREATE TABLE redundant_join_fact ( x INTEGER NOT NULL ); CREATE TABLE redundant_join_dimension ( y INTEGER NOT NULL ); INSERT INTO redundant_join_fact (x) SELECT g % 100 FROM generate_series(1, 100000) AS g; INSERT INTO redundant_join_dimension (y) SELECT g FROM generate_series(1, 10) AS g; ANALYZE redundant_join_fact; ANALYZE redundant_join_dimension; -- Place the JIT threshold between the two estimated plan costs. SET jit_above_cost =3D 11000; SET jit_inline_above_cost =3D 0; SET jit_optimize_above_cost =3D 0; -- Original predicate P. Estimated cost is about 13,694, so optimized JIT is -- enabled. The result is 47,605,000. EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, TIMING OFF) SELECT SUM(f.x + d.y) FROM redundant_join_fact AS f CROSS JOIN redundant_join_dimension AS d WHERE f.x < 30 OR f.x > 46; -- Equivalent P AND P. Estimated cost falls to about 10,333, below -- jit_above_cost. The result remains 47,605,000. EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, TIMING OFF) SELECT SUM(f.x + d.y) FROM redundant_join_fact AS f CROSS JOIN redundant_join_dimension AS d WHERE (f.x < 30 OR f.x > 46) AND (f.x < 30 OR f.x > 46); RESET jit_above_cost; RESET jit_inline_above_cost; RESET jit_optimize_above_cost; ``` On the tested server, both queries process the same 830,000 joined rows. The characteristic output is: ```text P: estimated fact rows: 67,143 total cost: 13,694.16 JIT Options: Inlining true, Optimization true Execution Time: 198.767 ms P AND P: estimated fact rows: 45,082 total cost: 10,333.49 no JIT section Execution Time: 41.958 ms ``` The redundant form is approximately 4.74x faster in the minimized case. Exact times depend on CPU and JIT state, but the estimate reduction and threshold crossing are deterministic with the tested version.