overlap between
the ranges of values assigned to different partitions. For
example, one might partition by date ranges, or by ranges of
identifiers for particular business objects.
Each range's bounds are understood as being inclusive at the
lower end and exclusive at the upper end. For example, if one
partition's range is from <literal>1</literal>
to <literal>10</literal>, and the next one's range is
from <literal>10</literal> to <literal>20</literal>, then
value <literal>10</literal> belongs to the second partition not
the first.
</para>
</listitem>
</varlistentry>
<varlistentry id="ddl-partitioning-overview-list">
<term>List Partitioning</term>
<listitem>
<para>
The table is partitioned by explicitly listing which key value(s)
appear in each partition.
</para>
</listitem>
</varlistentry>
<varlistentry id="ddl-partitioning-overview-hash">
<term>Hash Partitioning</term>
<listitem>
<para>
The table is partitioned by specifying a modulus and a remainder for
each partition. Each partition will hold the rows for which the hash
value of the partition key divided by the specified modulus will
produce the specified remainder.
</para>
</listitem>
</varlistentry>
</variablelist>
If your application needs to use other forms of partitioning not listed
above, alternative methods such as inheritance and
<literal>UNION ALL</literal> views can be used instead. Such methods
offer flexibility but do not have some of the performance benefits
of built-in declarative partitioning.
</para>
</sect2>
<sect2 id="ddl-partitioning-declarative">
<title>Declarative Partitioning</title>
<para>
<productname>PostgreSQL</productname> allows you to declare
that a table is divided into partitions. The table that is divided
is referred to as a <firstterm>partitioned table</firstterm>. The
declaration includes the <firstterm>partitioning method</firstterm>
as described above, plus a list of columns or expressions to be used
as the <firstterm>partition key</firstterm>.
</para>
<para>
The partitioned table itself is a <quote>virtual</quote> table having
no storage of its own. Instead, the storage belongs
to <firstterm>partitions</firstterm>, which are otherwise-ordinary
tables associated with the partitioned table.
Each partition stores a subset of the data as defined by its
<firstterm>partition bounds</firstterm>.
All rows inserted into a partitioned table will be routed to the
appropriate one of the partitions based on the values of the partition
key column(s).
Updating the partition key of a row will cause it to be moved into a
different partition if it no longer satisfies the partition bounds
of its original partition.
</para>
<para>
Partitions may themselves be defined as partitioned tables, resulting
in <firstterm>sub-partitioning</firstterm>. Although all partitions
must have the same columns as their partitioned parent, partitions may
have their
own indexes, constraints and default values, distinct from those of other
partitions. See <xref linkend="sql-createtable"/> for more details on
creating partitioned tables and partitions.
</para>
<para>
It is not possible to turn a regular table into a partitioned table or
vice versa. However, it is possible to add an existing regular or
partitioned table as a partition of a partitioned table, or remove a
partition from a partitioned table turning it into a standalone table;
this can simplify and speed up many maintenance processes.
See <xref linkend="sql-altertable"/> to learn more about the
<command>ATTACH PARTITION</command> and <command>DETACH PARTITION</command>