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 1tnN8i-004haY-10 for pgsql-hackers@arkaria.postgresql.org; Wed, 26 Feb 2025 19:32:16 +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 1tnN8g-00CKJq-UN for pgsql-hackers@arkaria.postgresql.org; Wed, 26 Feb 2025 19:32:14 +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.94.2) (envelope-from ) id 1tnN8g-00CKJA-GT for pgsql-hackers@lists.postgresql.org; Wed, 26 Feb 2025 19:32:14 +0000 Received: from mail-pj1-x1032.google.com ([2607:f8b0:4864:20::1032]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1tnN8d-000EsT-13 for pgsql-hackers@lists.postgresql.org; Wed, 26 Feb 2025 19:32:13 +0000 Received: by mail-pj1-x1032.google.com with SMTP id 98e67ed59e1d1-2fc33aef343so455007a91.1 for ; Wed, 26 Feb 2025 11:32:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740598331; x=1741203131; darn=lists.postgresql.org; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=+cCC46UVfgLWu/No5lPskQhjDoiZFPsFSVhWibz1STM=; b=bnco7WUhWntIuq/Ew+8whrRYqbNphK4L80XeUjDNSXqSh9QdVZ0Nw4jAS3BZZkh+sr v2WiPRPWeQOZ4hMhzLazeUDJLCJBculciHIEKhjn5xR42PoEfkOtyiojiaFFas4XmefU E5Zf+LR78nPla/FUn0m+FCOfrf/k9rUsyI+MqsqBFblKivSQh6Un30ZmC4BgJa3i1Vqu ATkQW5W0ptOMaBOPlbiKXzCK9BiRalrp9B703IqzeGFe4A3MUjNfshnosSuVbhOBu/Bl ouWDAwhY+KSaselvKPqJ7q2gJFPa2jPMJ66bGEvxa2oFOKTH3f+xHtttykETrKAnxJdv fV2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740598331; x=1741203131; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=+cCC46UVfgLWu/No5lPskQhjDoiZFPsFSVhWibz1STM=; b=wbiWOaPx7C2qJ868CTY5RdiAcoDdP+Dzb+stEUQtDOkA6yeHn3QKHQfCGG3bf+2qVI 37MnXDbb+4l2P6BjtTbKEr/BFyEhguPtKtLq+OkkMKVbZk817nxp4s6pKv9Gs4iJ6967 5LLVQy5TIB7EWDHEsC+N5R6iQK2SMIzprrs9U54gdzCUa6h6fQgz5E3LQYqcPYz3YPoz /eVtDzNYOGdN+IncCTO+JhpKWSHE2ycVhU8LNmIZCXR8GhxBsRGNKB1kd61l4wFJPjB2 IEHicG3zG8W7J2ICveJDgwzbInWXhc2bhGB6SMboNxfDIjYXdLefbUG+4KIAL5eWk5Qk nvsA== X-Gm-Message-State: AOJu0Yyiz46X7R+wTst9P2q+B/RyxEI49ij3NKDa93IUoksQIb5xJh6w +M46iAxMZY2ZdedA/sNXCtbjw0YMDx24CPD77pjw+BHjZsY95i2HSX9u3QjwRvLuNTir/7WWfnm DIbvwbh7aAdmBR7ZQmzN7OdAxQPkvxWgu X-Gm-Gg: ASbGncvYd5peESIrfjTGPc01jKAX8/MVo0t8xnyGh5ZUV9K5qOu250IE5Q002EYGxBc Ok15Pok6TgkPd+iSjaYS6b8Ny0WilOZZeNGbwYcrGzohYNFRrHw8xwWqhJXbfgbDQViS49vPDWA bC7mNciw== X-Google-Smtp-Source: AGHT+IE1RDKryPmuR5DTtK+pMAsRLeh2ff9+Xi5/mALrRspN/qcF07zdc/NZUEcnVXE9MedSplRCzOlO72nJJjfbHKk= X-Received: by 2002:a17:90a:da87:b0:2ee:48bf:7dc9 with SMTP id 98e67ed59e1d1-2fe7e3294d6mr7794045a91.15.1740598331052; Wed, 26 Feb 2025 11:32:11 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Dmytro Astapov Date: Wed, 26 Feb 2025 19:31:58 +0000 X-Gm-Features: AQ5f1JomhL8H44oKbL02fg0h1GuYVSkU8-CED6nM602BsMjmMMekK_TtxoczEZM Message-ID: Subject: Re: Relaxing constraints on BitmapAnd eligibility? To: pgsql-hackers@lists.postgresql.org Content-Type: multipart/mixed; boundary="000000000000385278062f10a102" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000385278062f10a102 Content-Type: multipart/alternative; boundary="000000000000385277062f10a100" --000000000000385277062f10a100 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi! I am (still) very unsure if the code change I mentioned will make sense, but documentation chage could perhaps look like something along these lines= ? Best regards, Dmytro On Tue, Feb 25, 2025 at 9:14=E2=80=AFPM Dmytro Astapov = wrote: > Hi! > > I've been investigating why postgres does not do BitmapAnd of two > well-suited indexes, and reading indxpath.c > > In my case, there is a table (d date, col1 int, col2 int) -- types not > really important -- and there are two indices on (d,col1) and (d, col2). > > For queries that do WHERE d>=3DX AND col1=3DY AND col2=3DZ postgres will = never > BitmapAnd those two indices because both indexes include (d) and we have = a > condition on (d). Here is a full example, which could also be seen here: > https://www.db-fiddle.com/f/uPLx5bRtDEoZw3Dx4kkwKh/0: > > begin; > > CREATE TABLE test_table ( > d date, > col1 int, > col2 int > ); > > INSERT INTO test_table (d, col1, col2) > SELECT > d.date, > c1.val as col1, > c2.val as col2 > FROM > generate_series( > '2023-01-01'::date, > '2023-12-31'::date, > '1 day'::interval > ) as d(date), > generate_series(1, 1000) as c1(val), > generate_series(1, 1000) as c2(val) > WHERE > random() < 0.001; > > create index on test_table(col1,d); > create index on test_table(col2,d); > > -- This uses BitmapAnd > explain select * from test_table where col1=3D123 and col2=3D321; > > -- This does not use BitmapAnd, even though it could! > explain select * from test_table where col1=3D123 and col2=3D321 and d >= =3D > '2023-05-05'; > > I checked that BitmapAnd is rejected by this > > line in choose_bitmap_and: > > if (bms_overlap(pathinfo->clauseids, clauseidsofar)) > continue; /* consider it redundant */ > > There is a comment on choose_bitmap_and that explains the rationale of > this check, but reading it I can't help but feel that what the comment > describes is this condition: > > if (bms_is_subset(pathinfo->clauseids, clauseidsofar)) > continue; /* consider it redundant */ > > And indeed, in my (admittedly not super-extensive) testing changing > bms_overlap to bms_is_subset leads to better faster execution plans. > > Is it possible that this condition could thus be relaxed? > > Even if I am wrong, and the condition absolutely should be bms_overlap, I > feel that this restriction is very very hard to discover and perhaps > https://www.postgresql.org/docs/current/indexes-bitmap-scans.html should > mention that compound indexes that have columns in common will never be > combined? > > Best regards, Dmytro > --000000000000385277062f10a100 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi!

I am (still) very unsure= if the code change I mentioned will make sense, but documentation chage co= uld perhaps look like something along these lines?



Best regards, Dmy= tro


On Tue, Feb 25, 2025 a= t 9:14=E2=80=AFPM Dmytro Astapov <= dastapov@gmail.com> wrote:
Hi!

I'= ve been investigating why postgres does not do BitmapAnd of two well-suited= indexes, and reading indxpath.c

In my case, there= is a table (d date, col1 int, col2 int) -- types not really important -- a= nd there are two indices on (d,col1) and (d, col2).

For queries that do WHERE d>=3DX AND col1=3DY AND col2=3DZ postgres wi= ll never BitmapAnd those two indices because both indexes include (d) and w= e have a condition on (d). Here is a full example, which could also be seen= here: https://www.db-fiddle.com/f/uPLx5bRtDEoZw3Dx4kkwKh/0:

begin;

CREATE TABLE test_table (
=C2=A0 = =C2=A0 d date,
=C2=A0 =C2=A0 col1 int,
=C2=A0 =C2=A0 col2 int
);
INSERT INTO test_table (d, col1, col2)
SELECT
=C2=A0 =C2=A0 d.d= ate,
=C2=A0 =C2=A0 c1.val as col1,
=C2=A0 =C2=A0 c2.val as col2
FR= OM
=C2=A0 =C2=A0 generate_series(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 '20= 23-01-01'::date,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 '2023-12-31'::d= ate,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 '1 day'::interval
=C2=A0 =C2= =A0 ) as d(date),
=C2=A0 =C2=A0 generate_series(1, 1000) as c1(val),
= =C2=A0 =C2=A0 generate_series(1, 1000) as c2(val)
WHERE
=C2=A0 =C2=A0= random() < 0.001;

create index on test_table(col1,d);
create = index on test_table(col2,d);

-- This uses Bitm= apAnd
explain select * from test_table where col1=3D123 and col2= =3D321;

-- This does not use BitmapAnd, even though it could!
exp= lain select * from test_table where col1=3D123 and col2=3D321 and d >=3D= '2023-05-05';

I checked that BitmapAnd is= rejected by this line = in choose_bitmap_and:

=C2=A0 =C2=A0if (bms_overlap= (pathinfo->clauseids, clauseidsofar))
=C2=A0 =C2=A0 =C2=A0 continue; = /* consider it redundant */

There is a comment on= choose_bitmap_and that explains the rationale of this check, but reading i= t I can't help but feel that what the comment describes=C2=A0is this co= ndition:

=C2=A0 =C2=A0if (bms_is_subset(pathi= nfo->clauseids, clauseidsofar))
=C2=A0 =C2=A0 =C2=A0 continue; /* con= sider it redundant */

And indeed, in my (admittedly no= t super-extensive) testing changing bms_overlap to bms_is_subset leads to b= etter faster execution plans.=C2=A0

Is it possible= that this condition could thus be relaxed?

Even i= f I am wrong, and the condition absolutely should be bms_overlap, I feel th= at this restriction is very very hard to discover and perhaps=C2=A0https://www.postgresql.org/docs/current/indexes-bitmap-scans.= html should mention that compound indexes that have columns in common w= ill never be combined?

Best regards, Dmytro
<= /div>
--000000000000385277062f10a100-- --000000000000385278062f10a102 Content-Type: text/x-patch; charset="US-ASCII"; name="v1-0001-Bitmap-restrictions.patch" Content-Disposition: attachment; filename="v1-0001-Bitmap-restrictions.patch" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_m7mban7k0 ZGlmZiAtLWdpdCBhL2RvYy9zcmMvc2dtbC9pbmRpY2VzLnNnbWwgYi9kb2Mvc3JjL3NnbWwvaW5k aWNlcy5zZ21sCmluZGV4IDZkNzMxZTA3MDEuLmRlNjNkMjNkN2IgMTAwNjQ0Ci0tLSBhL2RvYy9z cmMvc2dtbC9pbmRpY2VzLnNnbWwKKysrIGIvZG9jL3NyYy9zZ21sL2luZGljZXMuc2dtbApAQCAt NjgyLDYgKzY4MiwxNSBAQCBDUkVBVEUgSU5ERVggdGVzdDNfZGVzY19pbmRleCBPTiB0ZXN0MyAo aWQgREVTQyBOVUxMUyBMQVNUKTsKICAgIGJlc3QgbWF0Y2ggdGhlIGNvbW1vbiB0eXBlcy4KICAg PC9wYXJhPgogCisgIDxwYXJhPgorICAgIE5vdGUgdGhhdCBpZiB0aGVyZSBhcmUgbXVsdGlwbGUg aW5kZXhlcyBmb3IgYSBnaXZlbiBjb2x1bW4sIHRoZXkgd291bGQKKyAgICBuZXZlciBiZSBjb21i aW5lZC4gRm9yIGV4YW1wbGUsIGlmIHlvdSBoYXZlIG11bHRpY29sdW1uIGluZGV4ZXMKKyAgICBv biA8bGl0ZXJhbD4oeCwgeik8L2xpdGVyYWw+IGFuZCA8bGl0ZXJhbD4oeSwgeik8L2xpdGVyYWw+ LCB0aGV5IHdvdWxkCisgICAgbmV2ZXIgYmUgY29tYmluZWQgZm9yIHF1ZXJpZXMgaW52b2x2aW5n IDxsaXRlcmFsPno8L2xpdGVyYWw+LiBIb3dldmVyLCBpZgorICAgIHlvdXIgcXVlcnkgb25seSBp bnZvbHZlcyA8bGl0ZXJhbD54PC9saXRlcmFsPiBhbmQgPGxpdGVyYWw+eTwvbGl0ZXJhbD4sCisg ICAgdGhlbiBwbGFubmVyIGNhbiBwb3RlbnRpYWxseSBjaG9vc2UgdG8gY29tYmluZSB0aG9zZSBp bmRleGVzLgorICA8L3BhcmE+CisKICA8L3NlY3QxPgogCiAK --000000000000385278062f10a102--