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 1vIVGs-003WOA-1s for pgsql-performance@arkaria.postgresql.org; Mon, 10 Nov 2025 17:01:37 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vIVFq-001etz-2z for pgsql-performance@arkaria.postgresql.org; Mon, 10 Nov 2025 17:00:34 +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.96) (envelope-from ) id 1vIVFq-001etp-1N for pgsql-performance@lists.postgresql.org; Mon, 10 Nov 2025 17:00:34 +0000 Received: from mail-wr1-x42d.google.com ([2a00:1450:4864:20::42d]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vIVFn-0070zM-2i for pgsql-performance@lists.postgresql.org; Mon, 10 Nov 2025 17:00:34 +0000 Received: by mail-wr1-x42d.google.com with SMTP id ffacd0b85a97d-429c7f4f8a2so1591246f8f.0 for ; Mon, 10 Nov 2025 09:00:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bowt-ie.20230601.gappssmtp.com; s=20230601; t=1762794029; x=1763398829; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=ZeGgpYki4q42GFOEbuhm0e2Lsfwcjc1HPclE1anCqRk=; b=3Dp1SYTgVjR1Wuzw50HdpiXrVV1ID7jyFaqehmMi4u4eeTbNAlQ35kPV0MbKaVJoV3 uq5l592Quj3meavbNyU5ObB6kAItOtkvG5FPtf3pEZ8xXgu2c7Ypfn03gHqtXTZjKcoS iswXAQF1MhPUdkDwNvPA2hpxKNVrSAb2lA7MDmNbsKERpgJ9M2yffREjPYMipCDDuU6o rANO/1WvXSjadcDUzRXglCGeyuN0aP+L6021KOfgsTov1iqRWoVu2voWLTKOgeLCW3XD 5E8pUiuhb2ZcZiF3poK8VkVuAJeH4BPvdU6HdoV/KfQe+ANUQ7MbTHBE6OKmQAsVPvS9 ZQag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762794029; x=1763398829; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ZeGgpYki4q42GFOEbuhm0e2Lsfwcjc1HPclE1anCqRk=; b=e0KjpWHA7SkyFWHslDOGaGGlJi/puRxwgiYIZlhSZUHo8nszltG6OUy1iY/9E15IC3 duFPN8ghfdMM9KyECJ64tfM/tLr7E/zVV7jn4zoExg3P5F/Di/JWtMBlkTeQIEFSj3n7 Mf/exZQS5UTsWZhUbyMMv+eRiwJl6pYuCxQNUpP2d4X3MSD238Tz8lP1J0qIHmT50pz/ bHVCP6SNkrZ2JoxI6O6OhPlxqHnSARh6sq/CN4hDobVDwnNCEa/7lyAqFmVs2NTGsvaq S+E9oB2U30WqJX0ARKAnPrip9s50kRwHm6Bhde/wffhjXdX4IlP1ncFeK/qV3KbQ4LSz PpXw== X-Gm-Message-State: AOJu0YykQkt88NGBNWhI1aPGBXJ66a3KSpj9/sF/2Pjkf54R18zyQ0X+ Ct8wLfV7VPr9fdTdW8wlBcroaS7QOnM+ESjuKJqKWSlMP8WyNlz97cF9qGOQKJldmcHHoR3K6Gb cK8EmCUu9vUOl4J0K6OIM96M9WjBxChvvt2dH+B6bHTmuPucXMHxe34RS+A== X-Gm-Gg: ASbGncugxKGX1WCoLCOhXVPSMhe1nWw8oXvoET/JKa6iyqspdMswHF6rwdefmaBQUmA Lmulotx9bIZWwiomu4sOmpuo9D0w/qGomwHV+LToTXwRz6hTjvGe/bP0ZF5r5JYuEZi8sTk9a8p X9+4uh4Z1Ug0WwfJNHp2kDuGEXk2/RfokeIWkyKzRHq8mssGjH3rg3zBDa1dHgN+n/XiotFduKs /6guXDYKFVWhvaAoA8rY8US5SBkWS/lUCHD22U+kWM7k16s50pftuWJyyHhAbA7Dj44ngU= X-Google-Smtp-Source: AGHT+IE+8S363SRAlKIguxkWIKljKnGwzXZ7XVkiDSOEDDLPWQwKn8JIpRAqdhg3k90jj3oxR+mMZ8lxB0avkEBhCf0= X-Received: by 2002:a05:6000:280b:b0:42b:2a41:f20 with SMTP id ffacd0b85a97d-42b432be1bemr58553f8f.18.1762794028863; Mon, 10 Nov 2025 09:00:28 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Peter Geoghegan Date: Mon, 10 Nov 2025 12:00:02 -0500 X-Gm-Features: AWmQ_blkyMMhi-IajOMz6-L3pOgIHllIGFbukM6elytVci9cNKQtv1UyHBVo1-Y Message-ID: Subject: Re: Multicolumn index scan efficiency To: Vitalii Tymchyshyn Cc: pgsql-performance@lists.postgresql.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Mon, Nov 10, 2025 at 12:12=E2=80=AFAM Vitalii Tymchyshyn wr= ote: > Thank you so much for both clarifying and fixing it! FWIW the problem is limited to row compares/row constructor comparisons that are used to decide when to end the scan. Note in particular that row compares that decide where in the index (what leaf page) the scan should *begin* from were never affected -- only those that determine where the scan should end. In other words, for a forwards scan, > and >=3D row compares aren't affected (but < and <=3D row compares are). For backwards scans/with ORDER BY a DESC, b DESC, it's exactly the other way around (it's > and >=3D row compares that'll end the scan/that had this problem). My guess is that this issue wasn't noticed sooner because in practice a lot of users of row compares only use them to determine where each scan begins from, in the context of apply row compares to implement keyset pagination [1]. I think that it's typical to use an ORDER BY ... LIMIT, or a FETCH FIRST ... ROWS WITH TIES to limit the size of the result set on each individual query. It was a nasty and surprising issue, but it didn't actually come up all that often. After all, if you use a < or a <=3D condition to end each scan, the total number of rows that'll be returned each time is unpredictable -- and potentially very large. That isn't generally desirable with keyset pagination; what users usually do is have Postgres return a more or less uniform number of rows for each individual query that fetches the next portion of the "total result set". That's kinda the natural way to do it. [1] https://wiki.postgresql.org/images/3/35/Pagination_Done_the_PostgreSQL_= Way.pdf --=20 Peter Geoghegan