summaryrefslogtreecommitdiff
path: root/doc/src/sgml/btree.sgml
diff options
context:
space:
mode:
authorPeter Geoghegan2025-04-04 16:27:04 +0000
committerPeter Geoghegan2025-04-04 16:27:04 +0000
commit92fe23d93aa3bbbc40fca669cabc4a4d7975e327 (patch)
treee79d024c849f0a0b89378ff8c16b6d6b2d0cc777 /doc/src/sgml/btree.sgml
parent3ba2cdaa45416196fadc7163998cda7b4e07e7d7 (diff)
Add nbtree skip scan optimization.
Teach nbtree multi-column index scans to opportunistically skip over irrelevant sections of the index given a query with no "=" conditions on one or more prefix index columns. When nbtree is passed input scan keys derived from a predicate "WHERE b = 5", new nbtree preprocessing steps output "WHERE a = ANY(<every possible 'a' value>) AND b = 5" scan keys. That is, preprocessing generates a "skip array" (and an output scan key) for the omitted prefix column "a", which makes it safe to mark the scan key on "b" as required to continue the scan. The scan is therefore able to repeatedly reposition itself by applying both the "a" and "b" keys. A skip array has "elements" that are generated procedurally and on demand, but otherwise works just like a regular ScalarArrayOp array. Preprocessing can freely add a skip array before or after any input ScalarArrayOp arrays. Index scans with a skip array decide when and where to reposition the scan using the same approach as any other scan with array keys. This design builds on the design for array advancement and primitive scan scheduling added to Postgres 17 by commit 5bf748b8. Testing has shown that skip scans of an index with a low cardinality skipped prefix column can be multiple orders of magnitude faster than an equivalent full index scan (or sequential scan). In general, the cardinality of the scan's skipped column(s) limits the number of leaf pages that can be skipped over. The core B-Tree operator classes on most discrete types generate their array elements with the help of their own custom skip support routine. This infrastructure gives nbtree a way to generate the next required array element by incrementing (or decrementing) the current array value. It can reduce the number of index descents in cases where the next possible indexable value frequently turns out to be the next value stored in the index. Opclasses that lack a skip support routine fall back on having nbtree "increment" (or "decrement") a skip array's current element by setting the NEXT (or PRIOR) scan key flag, without directly changing the scan key's sk_argument. These sentinel values behave just like any other value from an array -- though they can never locate equal index tuples (they can only locate the next group of index tuples containing the next set of non-sentinel values that the scan's arrays need to advance to). A skip array's range is constrained by "contradictory" inequality keys. For example, a skip array on "x" will only generate the values 1 and 2 given a qual such as "WHERE x BETWEEN 1 AND 2 AND y = 66". Such a skip array qual usually has near-identical performance characteristics to a comparable SAOP qual "WHERE x = ANY('{1, 2}') AND y = 66". However, improved performance isn't guaranteed. Much depends on physical index characteristics. B-Tree preprocessing is optimistic about skipping working out: it applies static, generic rules when determining where to generate skip arrays, which assumes that the runtime overhead of maintaining skip arrays will pay for itself -- or lead to only a modest performance loss. As things stand, these assumptions are much too optimistic: skip array maintenance will lead to unacceptable regressions with unsympathetic queries (queries whose scan can't skip over many irrelevant leaf pages). An upcoming commit will address the problems in this area by enhancing _bt_readpage's approach to saving cycles on scan key evaluation, making it work in a way that directly considers the needs of = array keys (particularly = skip array keys). Author: Peter Geoghegan <[email protected]> Reviewed-By: Masahiro Ikeda <[email protected]> Reviewed-By: Heikki Linnakangas <[email protected]> Reviewed-By: Matthias van de Meent <[email protected]> Reviewed-By: Tomas Vondra <[email protected]> Reviewed-By: Aleksander Alekseev <[email protected]> Reviewed-By: Alena Rybakina <[email protected]> Discussion: https://postgr.es/m/CAH2-Wzmn1YsLzOGgjAQZdn1STSG_y8qP__vggTaPAYXJP+G4bw@mail.gmail.com
Diffstat (limited to 'doc/src/sgml/btree.sgml')
-rw-r--r--doc/src/sgml/btree.sgml31
1 files changed, 30 insertions, 1 deletions
diff --git a/doc/src/sgml/btree.sgml b/doc/src/sgml/btree.sgml
index 2b3997988cf..027361f20bb 100644
--- a/doc/src/sgml/btree.sgml
+++ b/doc/src/sgml/btree.sgml
@@ -207,7 +207,7 @@
<para>
As shown in <xref linkend="xindex-btree-support-table"/>, btree defines
- one required and four optional support functions. The five
+ one required and five optional support functions. The six
user-defined methods are:
</para>
<variablelist>
@@ -583,6 +583,35 @@ options(<replaceable>relopts</replaceable> <type>local_relopts *</type>) returns
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><function>skipsupport</function></term>
+ <listitem>
+ <para>
+ Optionally, a btree operator family may provide a <firstterm>skip
+ support</firstterm> function, registered under support function number 6.
+ These functions give the B-tree code a way to iterate through every
+ possible value that can be represented by an operator class's underlying
+ input type, in key space order. This is used by the core code when it
+ applies the skip scan optimization. The APIs involved in this are
+ defined in <filename>src/include/utils/skipsupport.h</filename>.
+ </para>
+ <para>
+ Operator classes that do not provide a skip support function are still
+ eligible to use skip scan. The core code can still use its fallback
+ strategy, though that might be suboptimal for some discrete types. It
+ usually doesn't make sense (and may not even be feasible) for operator
+ classes on continuous types to provide a skip support function.
+ </para>
+ <para>
+ It is not sensible for an operator family to register a cross-type
+ <function>skipsupport</function> function, and attempting to do so will
+ result in an error. This is because determining the next indexable value
+ must happen by incrementing a value copied from an index tuple. The
+ values generated must all be of the same underlying data type (the
+ <quote>skipped</quote> index column's opclass input type).
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>