1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

CREATE INDEX ... INCLUDING (column[, ...])

Now indexes (but only B-tree for now) can contain "extra" column(s) which
doesn't participate in index structure, they are just stored in leaf
tuples. It allows to use index only scan by using single index instead
of two or more indexes.

Author: Anastasia Lubennikova with minor editorializing by me
Reviewers: David Rowley, Peter Geoghegan, Jeff Janes
This commit is contained in:
Teodor Sigaev
2016-04-08 19:31:49 +03:00
parent 339025c68f
commit 386e3d7609
68 changed files with 1321 additions and 256 deletions

View File

@ -3557,6 +3557,14 @@
<literal>pg_class.relnatts</literal>)</entry>
</row>
<row>
<entry><structfield>indnkeyatts</structfield></entry>
<entry><type>int2</type></entry>
<entry></entry>
<entry>The number of key columns in the index. "Key columns" are ordinary
index columns in contrast with "included" columns.</entry>
</row>
<row>
<entry><structfield>indisunique</structfield></entry>
<entry><type>bool</type></entry>

View File

@ -117,6 +117,8 @@ typedef struct IndexAmRoutine
bool amclusterable;
/* does AM handle predicate locks? */
bool ampredlocks;
/* does AM support columns included with clause INCLUDING? */
bool amcaninclude;
/* type of data stored in index, or InvalidOid if variable */
Oid amkeytype;
@ -858,7 +860,8 @@ amrestrpos (IndexScanDesc scan);
using <firstterm>unique indexes</>, which are indexes that disallow
multiple entries with identical keys. An access method that supports this
feature sets <structfield>amcanunique</> true.
(At present, only b-tree supports it.)
(At present, only B-tree supports it.) Columns which are present in the
<literal>INCLUDING</> clause are not used to enforce uniqueness.
</para>
<para>

View File

@ -643,7 +643,8 @@ CREATE INDEX test3_desc_index ON test3 (id DESC NULLS LAST);
Indexes can also be used to enforce uniqueness of a column's value,
or the uniqueness of the combined values of more than one column.
<synopsis>
CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> (<replaceable>column</replaceable> <optional>, ...</optional>);
CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> (<replaceable>column</replaceable> <optional>, ...</optional>)
<optional>INCLUDING (<replaceable>column</replaceable> <optional>, ...</optional>)</optional>;
</synopsis>
Currently, only B-tree indexes can be declared unique.
</para>
@ -652,7 +653,9 @@ CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</repla
When an index is declared unique, multiple table rows with equal
indexed values are not allowed. Null values are not considered
equal. A multicolumn unique index will only reject cases where all
indexed columns are equal in multiple rows.
indexed columns are equal in multiple rows. Columns included with clause
<literal>INCLUDING</literal> aren't used to enforce constraints (UNIQUE,
PRIMARY KEY, etc).
</para>
<para>

View File

@ -23,6 +23,7 @@ PostgreSQL documentation
<synopsis>
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> ] ON <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">method</replaceable> ]
( { <replaceable class="parameter">column_name</replaceable> | ( <replaceable class="parameter">expression</replaceable> ) } [ COLLATE <replaceable class="parameter">collation</replaceable> ] [ <replaceable class="parameter">opclass</replaceable> ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ INCLUDING ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ]
[ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ]
[ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ]
[ WHERE <replaceable class="parameter">predicate</replaceable> ]
@ -138,6 +139,35 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
</listitem>
</varlistentry>
<varlistentry>
<term><literal>INCLUDING</literal></term>
<listitem>
<para>
An optional <literal>INCLUDING</> clause allows a list of columns to be
specified which will be included in the index, in the non-key portion of
the index. Columns which are part of this clause cannot also exist in
the key columns portion of the index, and vice versa. The
<literal>INCLUDING</> columns exist solely to allow more queries to
benefit from <firstterm>index-only scans</> by including certain
columns in the index, the value of which would otherwise have to be
obtained by reading
the table's heap. Having these columns in the <literal>INCLUDING</>
clause in some cases allows <productname>PostgreSQL</> to skip the heap
read completely. This also allows <literal>UNIQUE</> indexes to be
defined on one set of columns, which can include another set of column
in the <literal>INCLUDING</> clause, on which the uniqueness is not
enforced upon. It's the same with other constraints (PRIMARY KEY and
EXCLUDE). This can also can be used for non-unique indexes as any
columns which are not required for the searching or ordering of records
can be included in the <literal>INCLUDING</> clause, which can slightly
reduce the size of the index, due to storing included attributes only
in leaf index pages. Currently, only the B-tree access method supports
this feature. Expressions as included columns are not supported since
they cannot be used in index-only scan.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
@ -599,13 +629,22 @@ Indexes:
<title>Examples</title>
<para>
To create a B-tree index on the column <literal>title</literal> in
To create a unique B-tree index on the column <literal>title</literal> in
the table <literal>films</literal>:
<programlisting>
CREATE UNIQUE INDEX title_idx ON films (title);
</programlisting>
</para>
<para>
To create a unique B-tree index on the column <literal>title</literal>
and included columns <literal>director</literal> and <literal>rating</literal>
in the table <literal>films</literal>:
<programlisting>
CREATE UNIQUE INDEX title_idx ON films (title) INCLUDING (director, rating);
</programlisting>
</para>
<para>
To create an index on the expression <literal>lower(title)</>,
allowing efficient case-insensitive searches:

View File

@ -59,8 +59,8 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
{ CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) [ NO INHERIT ] |
UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> <optional>INCLUDING (<replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional> |
PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> <optional>INCLUDING (<replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional> |
EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
FOREIGN KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
@ -476,8 +476,8 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
<varlistentry>
<term><literal>UNIQUE</> (column constraint)</term>
<term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
<term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )
<optional>INCLUDING ( <replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional></> (table constraint)</term>
<listitem>
<para>
The <literal>UNIQUE</literal> constraint specifies that a
@ -498,12 +498,26 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
primary key constraint defined for the table. (Otherwise it
would just be the same constraint listed twice.)
</para>
<para>
Adding a unique constraint will automatically create a unique btree
index on the column or group of columns used in the constraint.
Optional clause <literal>INCLUDING</literal> allows to add into the index
a portion of columns on which the uniqueness is not enforced upon.
Note, that althogh constraint is not enforced upon included columns, it still
depends on them. Consequently, some operations on these columns (e.g. <literal>DROP COLUMN</literal>)
can cause cascade constraint and index deletion.
See paragraph about <literal>INCLUDING</literal> in
<xref linkend="SQL-CREATEINDEX"> for more information.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>PRIMARY KEY</> (column constraint)</term>
<term><literal>PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
<term><literal>PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )
<optional>INCLUDING ( <replaceable class="PARAMETER">column_name</replaceable> [, ...])</optional></> (table constraint)</term>
<listitem>
<para>
The <literal>PRIMARY KEY</> constraint specifies that a column or
@ -526,6 +540,18 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
about the design of the schema, since a primary key implies that other
tables can rely on this set of columns as a unique identifier for rows.
</para>
<para>
Adding a <literal>PRIMARY KEY</literal> constraint will automatically create a unique btree
index on the column or group of columns used in the constraint.
Optional clause <literal>INCLUDING</literal> allows to add into the index
a portion of columns on which the constraint is not enforced upon.
Note, that althogh constraint is not enforced upon included columns, it still
depends on them. Consequently, some operations on these columns (e.g. <literal>DROP COLUMN</literal>)
can cause cascade constraint and index deletion.
See paragraph about <literal>INCLUDING</literal> in
<xref linkend="SQL-CREATEINDEX"> for more information.
</para>
</listitem>
</varlistentry>