1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>11.3. Multicolumn Indexes</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="indexes-types.html" title="11.2. Index Types" /><link rel="next" href="indexes-ordering.html" title="11.4. Indexes and ORDER BY" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">11.3. Multicolumn Indexes</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="indexes-types.html" title="11.2. Index Types">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="indexes.html" title="Chapter 11. Indexes">Up</a></td><th width="60%" align="center">Chapter 11. Indexes</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="indexes-ordering.html" title="11.4. Indexes and ORDER BY">Next</a></td></tr></table><hr /></div><div class="sect1" id="INDEXES-MULTICOLUMN"><div class="titlepage"><div><div><h2 class="title" style="clear: both">11.3. Multicolumn Indexes <a href="#INDEXES-MULTICOLUMN" class="id_link">#</a></h2></div></div></div><a id="id-1.5.10.6.2" class="indexterm"></a><p>
3 An index can be defined on more than one column of a table. For example, if
4 you have a table of this form:
5 </p><pre class="programlisting">
12 (say, you keep your <code class="filename">/dev</code>
13 directory in a database...) and you frequently issue queries like:
14 </p><pre class="programlisting">
15 SELECT name FROM test2 WHERE major = <em class="replaceable"><code>constant</code></em> AND minor = <em class="replaceable"><code>constant</code></em>;
17 then it might be appropriate to define an index on the columns
18 <code class="structfield">major</code> and
19 <code class="structfield">minor</code> together, e.g.:
20 </p><pre class="programlisting">
21 CREATE INDEX test2_mm_idx ON test2 (major, minor);
24 Currently, only the B-tree, GiST, GIN, and BRIN index types support
25 multiple-key-column indexes. Whether there can be multiple key
26 columns is independent of whether <code class="literal">INCLUDE</code> columns
27 can be added to the index. Indexes can have up to 32 columns,
28 including <code class="literal">INCLUDE</code> columns. (This limit can be
29 altered when building <span class="productname">PostgreSQL</span>; see the
30 file <code class="filename">pg_config_manual.h</code>.)
32 A multicolumn B-tree index can be used with query conditions that
33 involve any subset of the index's columns, but the index is most
34 efficient when there are constraints on the leading (leftmost) columns.
35 The exact rule is that equality constraints on leading columns, plus
36 any inequality constraints on the first column that does not have an
37 equality constraint, will always be used to limit the portion of the index
38 that is scanned. Constraints on columns to the right of these columns
39 are checked in the index, so they'll always save visits to the table
40 proper, but they do not necessarily reduce the portion of the index that
41 has to be scanned. If a B-tree index scan can apply the skip scan
42 optimization effectively, it will apply every column constraint when
43 navigating through the index via repeated index searches. This can reduce
44 the portion of the index that has to be read, even though one or more
45 columns (prior to the least significant index column from the query
46 predicate) lacks a conventional equality constraint. Skip scan works by
47 generating a dynamic equality constraint internally, that matches every
48 possible value in an index column (though only given a column that lacks
49 an equality constraint that comes from the query predicate, and only when
50 the generated constraint can be used in conjunction with a later column
51 constraint from the query predicate).
53 For example, given an index on <code class="literal">(x, y)</code>, and a query
54 condition <code class="literal">WHERE y = 7700</code>, a B-tree index scan might be
55 able to apply the skip scan optimization. This generally happens when the
56 query planner expects that repeated <code class="literal">WHERE x = N AND y = 7700</code>
57 searches for every possible value of <code class="literal">N</code> (or for every
58 <code class="literal">x</code> value that is actually stored in the index) is the
59 fastest possible approach, given the available indexes on the table. This
60 approach is generally only taken when there are so few distinct
61 <code class="literal">x</code> values that the planner expects the scan to skip over
62 most of the index (because most of its leaf pages cannot possibly contain
63 relevant tuples). If there are many distinct <code class="literal">x</code> values,
64 then the entire index will have to be scanned, so in most cases the planner
65 will prefer a sequential table scan over using the index.
67 The skip scan optimization can also be applied selectively, during B-tree
68 scans that have at least some useful constraints from the query predicate.
69 For example, given an index on <code class="literal">(a, b, c)</code> and a
70 query condition <code class="literal">WHERE a = 5 AND b >= 42 AND c < 77</code>,
71 the index might have to be scanned from the first entry with
72 <code class="literal">a</code> = 5 and <code class="literal">b</code> = 42 up through the last
73 entry with <code class="literal">a</code> = 5. Index entries with
74 <code class="literal">c</code> >= 77 will never need to be filtered at the table
75 level, but it may or may not be profitable to skip over them within the
76 index. When skipping takes place, the scan starts a new index search to
77 reposition itself from the end of the current <code class="literal">a</code> = 5 and
78 <code class="literal">b</code> = N grouping (i.e. from the position in the index
79 where the first tuple <code class="literal">a = 5 AND b = N AND c >= 77</code>
80 appears), to the start of the next such grouping (i.e. the position in the
81 index where the first tuple <code class="literal">a = 5 AND b = N + 1</code>
84 A multicolumn GiST index can be used with query conditions that
85 involve any subset of the index's columns. Conditions on additional
86 columns restrict the entries returned by the index, but the condition on
87 the first column is the most important one for determining how much of
88 the index needs to be scanned. A GiST index will be relatively
89 ineffective if its first column has only a few distinct values, even if
90 there are many distinct values in additional columns.
92 A multicolumn GIN index can be used with query conditions that
93 involve any subset of the index's columns. Unlike B-tree or GiST,
94 index search effectiveness is the same regardless of which index column(s)
95 the query conditions use.
97 A multicolumn BRIN index can be used with query conditions that
98 involve any subset of the index's columns. Like GIN and unlike B-tree or
99 GiST, index search effectiveness is the same regardless of which index
100 column(s) the query conditions use. The only reason to have multiple BRIN
101 indexes instead of one multicolumn BRIN index on a single table is to have
102 a different <code class="literal">pages_per_range</code> storage parameter.
104 Of course, each column must be used with operators appropriate to the index
105 type; clauses that involve other operators will not be considered.
107 Multicolumn indexes should be used sparingly. In most situations,
108 an index on a single column is sufficient and saves space and time.
109 Indexes with more than three columns are unlikely to be helpful
110 unless the usage of the table is extremely stylized. See also
111 <a class="xref" href="indexes-bitmap-scans.html" title="11.5. Combining Multiple Indexes">Section 11.5</a> and
112 <a class="xref" href="indexes-index-only-scans.html" title="11.9. Index-Only Scans and Covering Indexes">Section 11.9</a> for some discussion of the
113 merits of different index configurations.
114 </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="indexes-types.html" title="11.2. Index Types">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="indexes.html" title="Chapter 11. Indexes">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="indexes-ordering.html" title="11.4. Indexes and ORDER BY">Next</a></td></tr><tr><td width="40%" align="left" valign="top">11.2. Index Types </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 11.4. Indexes and <code class="literal">ORDER BY</code></td></tr></table></div></body></html>