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 1vNrZd-00HYt7-3D for pgsql-hackers@arkaria.postgresql.org; Tue, 25 Nov 2025 11:51:10 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vNrZc-008EwH-2B for pgsql-hackers@arkaria.postgresql.org; Tue, 25 Nov 2025 11:51:08 +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 1vNrZc-008Ew8-1F for pgsql-hackers@lists.postgresql.org; Tue, 25 Nov 2025 11:51:08 +0000 Received: from mail.postgrespro.ru ([93.174.132.70]) by makus.postgresql.org with smtp (Exim 4.96) (envelope-from ) id 1vNrZW-001NPi-2j for pgsql-hackers@lists.postgresql.org; Tue, 25 Nov 2025 11:51:07 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=postgrespro.ru; s=mx2023; t=1764071460; bh=6NMkUG/JWSmGhDrbP6pKF4e/5Rf6UDh+yV3PZgc3lRk=; h=Message-ID:Date:User-Agent:Subject:To:Cc:References:From: In-Reply-To:From; b=VyK1KbQ5jNfuu4S2lT4A8H0egOwLQzxXCDZ9pZUIyHhBeHBFY/VYxV3rvIBBQJe1Z mgFf6KXOIK6Z0dbqnSaZWOuaWRIysH8nqD7RGCyzvfSkQrFcAWAnTOypf3FGm4nmQ+ mNhxaFXPsi3Vf0EqtEpcNcLs+iYtQ322ER5SrPFbub+vZpr5OwJcoh5ZTpZqhW/3dP ilo4cnGKbBVlYYoI9/q24vCs5/NdFkF0IC+U6ncifWVkuEw6VvvctuSKexl9bVwNeB NuOR7frZpijKfwgv86Rvk+k9qCCZsbRSsk8ctx/g5WZKPWkJuv1HrYZMMTnMiN5OOR fiGS0gWJ+W86Q== Received: from [192.168.1.41] (a96.sub49.net78.udm.net [78.85.49.96]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) (Authenticated sender: s.glukhov@postgrespro.ru) by mail.postgrespro.ru (Postfix/465) with ESMTPSA id 064086082F; Tue, 25 Nov 2025 14:50:59 +0300 (MSK) Message-ID: Date: Tue, 25 Nov 2025 15:50:59 +0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Partial hash index is not used for implied qual. To: Tom Lane , David Rowley Cc: pgsql-hackers@lists.postgresql.org References: <1106189.1764033798@sss.pgh.pa.us> <1112416.1764036072@sss.pgh.pa.us> Content-Language: en-US From: Sergei Glukhov In-Reply-To: <1112416.1764036072@sss.pgh.pa.us> Content-Type: text/plain; charset=UTF-8; format=flowed X-KSMG-AntiPhishing: NotDetected X-KSMG-AntiSpam-Interceptor-Info: not scanned X-KSMG-AntiSpam-Status: not scanned, disabled by settings X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.1.0.7854, bases: 2025/11/25 08:58:00 #27971987 X-KSMG-AntiVirus-Status: NotDetected, skipped X-KSMG-LinksScanning: not scanned, disabled by settings X-KSMG-Message-Action: skipped X-KSMG-Rule-ID: 1 Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, On 11/25/25 6:01 AM, Tom Lane wrote: > I wrote: >> Wouldn't it be better to handle it more like the is_target_rel logic >> a few lines further up? > Actually, after thinking a bit longer, it'd be better to do something > like the attached so that we don't keep redundant quals unless they'd > *all* be excluded. > > There's definitely something fishy about the costing though. > I experimented with this variant of Sergei's example: > > regression=3D# CREATE TABLE hash_partial(x) AS SELECT x % 100 as y from= generate_series(1, 1000) as x; > SELECT 1000 > regression=3D# ANALYZE hash_partial; > ANALYZE > regression=3D# CREATE INDEX partial_idx ON hash_partial USING hash(x) W= HERE x =3D 1; > CREATE INDEX > regression=3D# set enable_seqscan TO 0; -- else we'll go for a seqscan > SET > regression=3D# EXPLAIN SELECT x FROM hash_partial WHERE x =3D 1; > QUERY PLAN > -----------------------------------------------------------------------= ----- > Bitmap Heap Scan on hash_partial (cost=3D24.08..32.56 rows=3D10 widt= h=3D4) > Recheck Cond: (x =3D 1) > -> Bitmap Index Scan on partial_idx (cost=3D0.00..24.07 rows=3D10= width=3D0) > Index Cond: (x =3D 1) > (4 rows) > > regression=3D# drop index partial_idx; > DROP INDEX > regression=3D# CREATE INDEX ON hash_partial USING hash(x); > CREATE INDEX > regression=3D# EXPLAIN SELECT x FROM hash_partial WHERE x =3D 1; > QUERY PLAN > -----------------------------------------------------------------------= ----------- > Bitmap Heap Scan on hash_partial (cost=3D4.08..12.56 rows=3D10 width= =3D4) > Recheck Cond: (x =3D 1) > -> Bitmap Index Scan on hash_partial_x_idx (cost=3D0.00..4.08 row= s=3D10 width=3D0) > Index Cond: (x =3D 1) > (4 rows) > > Why are we thinking that a non-partial index would be substantially > cheaper to scan? That seems surely wrong, and it runs counter to my > intuition about why this fix is incomplete. (I expected an unfair > bias towards the partial index, not against it.) > > regards, tom lane > Thanks for the fix. It seems there is another case for investigation: DROP TABLE hash_partial; CREATE TABLE hash_partial(x, y) AS SELECT x, x + x as y from generate_series(1, 1000) as x; ANALYZE hash_partial; CREATE INDEX partial_idx=C2=A0 ON hash_partial USING hash(x) WHERE x =3D = 1; SET enable_seqscan TO 0; EXPLAIN SELECT x FROM hash_partial WHERE x =3D 1 and y < 0; -------------------------------------------------------------------------= ------- Seq Scan on hash_partial=C2=A0 (cost=3D0.00..23.00 rows=3D1 width=3D4) =C2=A0=C2=A0 Disabled: true =C2=A0=C2=A0 Filter: ((y < 0) AND (x =3D 1)) (3 rows) =C2=A0Regarding strangeness of the cost, =C2=A0cost is depends on numIndexPages and =C2=A0in genericcostestimate() we calulate numIndexPages: =C2=A0numIndexPages =3D ceil(numIndexTuples * index->pages / index->tupl= es); =C2=A0For non-partial index index->pages =3D 6 and index->tuples =3D 100= 0 =C2=A0and for partial index index->pages =3D 6 and index->tuples =3D 10. =C2=A0Number of pages depends on index relation size and =C2=A0initial size is 6 * BLCKSZ for both, partial and non-partial hash = indexes =C2=A0Initial size of the hash index relation, in turn, =C2=A0depends on total number of tuples in the table. =C2=A0Regards, =C2=A0Sergei Glukhov