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 1wmTrf-000o7g-0B 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-00BUZ8-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 1wmQw3-00Aq03-2L for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:00:07 +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 1wmQw0-00000001NkG-2BuS for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:00:06 +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=4DtFv5xP13FtYoCZ/ol5fNvW5m335XpnYzAPrM0PyW0=; b=KMNugIBLUz6t1u8r7iCuJVt6oM Afgm8HZr8sBkNIWpyD55QdT4yN2n0BwhiEt5PenhvY/3lzPdYcgW83MR6ZLj+w1hTlvD5OOYWyf+H 0h4PTV/L13ZhnoSr2UxD+07pOVKrqYlwEGS0UGjSO3r9IirdBSMJ6mWvkutuDyKXq0wvndBNJwnhe wKuuuo/gwxnhzBeOwp6tZaALSNkmNuJERoXdvwqglOY58ylZWfmYKifjBcBg7K720h8fguI2+kwK0 DCdWmlu5BRJZCGy40aLmao5w4TN8+MW9+7trvCxjTJo0gsNNIRi0x4ii5bq8LuXIIzmccDVd8/ACD KGs/fFBw==; 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 1wmQw0-001kxg-33 for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:00:04 +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 1wmQvz-000000026PO-3hq5 for pgsql-bugs@lists.postgresql.org; Wed, 22 Jul 2026 07:00:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19571: Semantically redundant OR FALSE prevents IN-subquery pull-up and causes a slower SubPlan 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 06:59:35 +0000 Message-ID: <19571-335e2c79294a2252@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: 19571 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 the Boolean identity `P OR FALSE =3D P`. The equivalence remains valid under SQL three-valued logic, including when `P` evaluates to NULL. When `P` is an `IN` subquery, PostgreSQL nevertheless optimizes the two forms differently. ### Expected Behaviour PostgreSQL should simplify `P OR FALSE` early enough that both forms are planned identically. In particular, the redundant constant should not prevent an `IN` subquery from being pulled up into a semijoin. ### Actual Behaviour The plain `IN` predicate becomes a `Hash Semi Join`. Wrapping the same predicate in `OR FALSE` leaves it as a hashed `SubPlan` attached to an outer sequential scan. In the standalone case, execution time increases from 7.143 ms to 13.810 ms, approximately 1.93x. The generated pair 837 shows a much larger order-stable instance: median time increases from 2.750 ms to 668.339 ms, approximately 243.9x. ## How to repeat ```sql DROP TABLE IF EXISTS identity_outer; DROP TABLE IF EXISTS identity_inner; CREATE TABLE identity_outer (v INTEGER NOT NULL); CREATE TABLE identity_inner (v INTEGER NOT NULL); INSERT INTO identity_outer SELECT g FROM generate_series(90001, 91000) AS g; INSERT INTO identity_inner SELECT g FROM generate_series(1, 100000) AS g; ANALYZE identity_outer; ANALYZE identity_inner; -- Original form P. EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, TIMING OFF) SELECT COUNT(*) FROM identity_outer AS o WHERE o.v IN ( SELECT i.v FROM identity_inner AS i ); -- Equivalent form P OR FALSE. EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, TIMING OFF) SELECT COUNT(*) FROM identity_outer AS o WHERE ( o.v IN (SELECT i.v FROM identity_inner AS i) ) OR FALSE; ``` Both queries return 1,000. Characteristic plans and measured times are: ```text P: Hash Semi Join Execution Time: 7.143 ms P OR FALSE: Seq Scan on identity_outer Filter: ANY (... hashed SubPlan 1 ...) Execution Time: 13.810 ms ```