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 1r88uN-008RTy-19 for pgsql-hackers@arkaria.postgresql.org; Wed, 29 Nov 2023 00:58:31 +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 1r88uJ-008BJD-SR for pgsql-hackers@arkaria.postgresql.org; Wed, 29 Nov 2023 00:58:27 +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.94.2) (envelope-from ) id 1r88uJ-008BJ5-FZ for pgsql-hackers@lists.postgresql.org; Wed, 29 Nov 2023 00:58:27 +0000 Received: from mail-vs1-xe2a.google.com ([2607:f8b0:4864:20::e2a]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1r88uC-00956X-N3 for pgsql-hackers@lists.postgresql.org; Wed, 29 Nov 2023 00:58:26 +0000 Received: by mail-vs1-xe2a.google.com with SMTP id ada2fe7eead31-46436ba83ecso381501137.1 for ; Tue, 28 Nov 2023 16:58:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bowt-ie.20230601.gappssmtp.com; s=20230601; t=1701219498; x=1701824298; 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=nnJKdV6FR3343qaMEXpXqNwgc/Tsg2MoV61/jdrztI0=; b=PbbxJrVxbLb/hw8dRhE34BlrHk9U6lnytCtKr94UDTdLA2encOJceRsZstKPBZqZ08 ADG6yv6/EL1qjBS6WdWZGtWyzI2iFfVPvcwLl/hvkimcRFI+43JZ3duwIpz8ZDE58jlX Y0dPHDu1d7ac/YdwcECHzI4+GeGqjCJG91ITf1nYhvL7mbZeUHhsXWVinBzifyFQLsJ5 XIF2KYt3ePtP4qo/LQ6uFH181ImmsvkjuEymJiCDme4FQ79oDRjBCoIjHjDqaa7kgbme Wrc+9AxpAB5VoKy+/FZu7pjCy9IX091MVudHz7ZztWh3az0qzN/b5UudsK9BLgACX3vo dDKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701219498; x=1701824298; h=content-transfer-encoding:cc: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=nnJKdV6FR3343qaMEXpXqNwgc/Tsg2MoV61/jdrztI0=; b=vrLkki5LhzDlVuDnBtxciSaXO/slVYBqP3w1B1CucVmB8NXMJLSkiSw6Sk0QkxtLV0 UuCiXWNV+41eK3ArMLtYlUaSD0EEsEoh93K0NyIO8kl5NoCBuxRm7tNaRNsjhBzIvF42 3BL3em2Jr9KGpwG/Ekv8Qz+ktzaTPQDLf6VSdddXBrSvf32RB8LyZeBlovBtjjUv2cHP +PP1a0tQSgsB7ziY21MKWAD6KlOrJziMCtcRv28TPN+xUwmb5h1THABlFNJYrA5f0aJ+ AOCqwZPoxOSaYfK/mqDgTVaL1q58b688kvWZHacMy5+Rqo4MzFRxb6YH23mz9zNaiIXv TEQw== X-Gm-Message-State: AOJu0YyxenNvraG9eXQgwJyPU7ldwSdEDctX+GvZFzclHpsLASA8JLGE K++MES3BSHj5hDxq+8kuOEi9L0ZdNvgjFQc+Iw4W3A== X-Google-Smtp-Source: AGHT+IHMx+gN29S1kk5KQbHRED0y+sOjKScDYPNdH1TSx5F0AafsWBzgBY0yL3wRIKkm4FkvnKwBZf2iE1nubMunj7w= X-Received: by 2002:a05:6102:945:b0:45d:b7f4:4639 with SMTP id a5-20020a056102094500b0045db7f44639mr14170758vsi.25.1701219498432; Tue, 28 Nov 2023 16:58:18 -0800 (PST) MIME-Version: 1.0 References: <9c35e090-2ee3-286d-fed0-7dd380bc0939@enterprisedb.com> In-Reply-To: From: Peter Geoghegan Date: Tue, 28 Nov 2023 16:57:52 -0800 Message-ID: Subject: Re: Optimizing nbtree ScalarArrayOp execution, allowing multi-column ordered scans, skip scan To: Tomas Vondra Cc: Matthias van de Meent , PostgreSQL Hackers , Tom Lane , Jeff Davis , benoit , Alexander Korotkov 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 Tue, Nov 28, 2023 at 3:52=E2=80=AFPM Peter Geoghegan wrote: > While I still think that we need heuristics that apply speculative > criteria to decide whether or not going to the next page directly > (when we have a choice at all), that doesn't mean that the v7 > heuristics can't be improved on, with a little more thought. It's a > bit tricky, since we're probably also benefiting from the same > heuristics all the time -- probably even for this same test case. Correction: this particular test case happens to be one where the optimal strategy is to do *exactly* what the master branch does currently. The master branch is unbeatable, so the only reasonable goal for the patch is to not lose (or to lose by no more than a completely negligible amount). I'm now prepared to say that this behavior is not okay -- I definitely need to fix this. It's a bug. Because each distinct value never fits on one leaf page (it's more like 1.5 - 2 pages, even though we're deduplicating heavily), and because Postgres 12 optimizations are so effective with low cardinality/posting-list-heavy indexes such as this, we're bound to lose quite often. The only reason it doesn't happen _every single time_ we descend the index is because the test script uses CREATE INDEX, rather than using retail inserts (I tend to prefer the latter for this sort of analysis). Since nbtsort.c isn't as clever/aggressive about suffix truncation as the nbtsplitloc.c split strategies would have been, had we used them (had there been retail inserts), many individual leaf pages are left with high keys that aren't particularly good targets for the high key precheck optimization (see Postgres 12 commit 29b64d1d). If I wanted to produce a truly adversarial case for this issue (which this is already close to), I'd go with the following: 1. Retail inserts that leave each leaf page full of one single value, which will allow each high key to still make a "clean break" from the right sibling page -- it'll have the right sibling's value. Maybe insert 1200 - 1300 tuples per distinct index value for this. In other words, bulk loading that results in an index that never has to append a heap TID tiebreaker during suffix truncation, but comes very close to needing to. Bulk loading where nbtsplitloc.c needs to use SPLIT_MANY_DUPLICATES all the time, but never quite gets to the point of needing a SPLIT_SINGLE_VALUE split. 2. A SAOP query with an array with every second value in the index as an element. Something like "WHERE arr in (2, 4, 6, 8, ...)". The patch will read every single leaf page, whereas master will *reliably* only read every second leaf page. I didn't need to "trick" the patch in a contrived sort of way to get this bad outcome -- this scenario is fairly realistic. So this behavior is definitely not something that I'm prepared to defend. As I said, it's a bug. It'll be fixed in the next revision. -- Peter Geoghegan