-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.49 2005/11/04 23:13:59 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.50 2005/11/04 23:53:18 tgl Exp $ -->
<chapter id="ddl">
<title>Data Definition</title>
Subsequently, we discuss how tables can be organized into
schemas, and how privileges can be assigned to tables. Finally,
we will briefly look at other features that affect the data storage,
- such as views, functions, and triggers.
+ such as inheritance, views, functions, and triggers.
</para>
<sect1 id="ddl-basics">
constraint described in the next section can be used.
</para>
- <para>
- Check constraints can also be used to enhance performance with
- very large tables, when used in conjunction with the <xref
- linkend="guc-constraint-exclusion"> parameter. This is discussed
- in more detail in <xref linkend="ce-partitioning">.
+ <para>
+ Check constraints can be useful for enhancing the performance of
+ partitioned tables. For details see <xref linkend="ddl-partitioning">.
</para>
</sect2>
<para>
The OID of the table containing this row. This column is
particularly handy for queries that select from inheritance
- hierarchies, since without it, it's difficult to tell which
- individual table a row came from. The
+ hierarchies (see <xref linkend="ddl-inherit">), since without it,
+ it's difficult to tell which individual table a row came from. The
<structfield>tableoid</structfield> can be joined against the
<structfield>oid</structfield> column of
<structname>pg_class</structname> to obtain the table name.
</para>
</sect1>
- <sect1 id="ddl-inherit">
- <title>Inheritance</title>
-
- <indexterm>
- <primary>not-null constraint</primary>
- </indexterm>
+ <sect1 id="ddl-alter">
+ <title>Modifying Tables</title>
- <indexterm>
- <primary>constraint</primary>
- <secondary>NOT NULL</secondary>
- </indexterm>
+ <indexterm zone="ddl-alter">
+ <primary>table</primary>
+ <secondary>modifying</secondary>
+ </indexterm>
<para>
- <productname>PostgreSQL</productname> implements table inheritance
- which can be a useful tool for database designers. SQL:1999 and
- later define a type inheritance feature, which differs in many
- respects from the features described here.
+ When you create a table and you realize that you made a mistake, or
+ the requirements of the application change, then you can drop the
+ table and create it again. But this is not a convenient option if
+ the table is already filled with data, or if the table is
+ referenced by other database objects (for instance a foreign key
+ constraint). Therefore <productname>PostgreSQL</productname>
+ provides a family of commands to make modifications to existing
+ tables. Note that this is conceptually distinct from altering
+ the data contained in the table: here we are interested in altering
+ the definition, or structure, of the table.
</para>
<para>
- Let's start with an example: suppose we are trying to build a data
- model for cities. Each state has many cities, but only one
- capital. We want to be able to quickly retrieve the capital city
- for any particular state. This can be done by creating two tables,
- one for state capitals and one for cities that are not
- capitals. However, what happens when we want to ask for data about
- a city, regardless of whether it is a capital or not? The
- inheritance feature can help to resolve this problem. We define the
- <literal>capitals</literal> table so that it inherits from
- <literal>cities</literal>:
-
-<programlisting>
-CREATE TABLE cities (
- name text,
- population float,
- altitude int -- in feet
-);
-
-CREATE TABLE capitals (
- state char(2)
-) INHERITS (cities);
-</programlisting>
+ You can
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>Add columns,</para>
+ </listitem>
+ <listitem>
+ <para>Remove columns,</para>
+ </listitem>
+ <listitem>
+ <para>Add constraints,</para>
+ </listitem>
+ <listitem>
+ <para>Remove constraints,</para>
+ </listitem>
+ <listitem>
+ <para>Change default values,</para>
+ </listitem>
+ <listitem>
+ <para>Change column data types,</para>
+ </listitem>
+ <listitem>
+ <para>Rename columns,</para>
+ </listitem>
+ <listitem>
+ <para>Rename tables.</para>
+ </listitem>
+ </itemizedlist>
- In this case, a row of <literal>capitals</> <firstterm>inherits</>
- all the columns of its parent table, <literal>cities</>. State
- capitals have an extra attribute, <literal>state</>, that shows
- their state.
+ All these actions are performed using the
+ <xref linkend="sql-altertable" endterm="sql-altertable-title">
+ command.
</para>
- <para>
- In <productname>PostgreSQL</productname>, a table can inherit from
- zero or more other tables, and a query can reference either all
- rows of a table or all rows of a table plus all of its descendants.
- For example, the following query finds the names of all cities,
- including state capitals, that are located at an altitude over
- 500ft:
+ <sect2>
+ <title>Adding a Column</title>
+
+ <indexterm>
+ <primary>column</primary>
+ <secondary>adding</secondary>
+ </indexterm>
+ <para>
+ To add a column, use a command like this:
<programlisting>
-SELECT name, altitude
- FROM cities
- WHERE altitude > 500;
+ALTER TABLE products ADD COLUMN description text;
</programlisting>
+ The new column is initially filled with whatever default
+ value is given (null if you don't specify a <literal>DEFAULT</> clause).
+ </para>
- which returns:
-
+ <para>
+ You can also define constraints on the column at the same time,
+ using the usual syntax:
<programlisting>
- name | altitude
------------+----------
- Las Vegas | 2174
- Mariposa | 1953
- Madison | 845
+ALTER TABLE products ADD COLUMN description text CHECK (description <> '');
</programlisting>
- </para>
+ In fact all the options that can be applied to a column description
+ in <command>CREATE TABLE</> can be used here. Keep in mind however
+ that the default value must satisfy the given constraints, or the
+ <literal>ADD</> will fail. Alternatively, you can add
+ constraints later (see below) after you've filled in the new column
+ correctly.
+ </para>
+ </sect2>
- <para>
- On the other hand, the following query finds all the cities that
- are not state capitals and are situated at an altitude over 500ft:
+ <sect2>
+ <title>Removing a Column</title>
-<programlisting>
-SELECT name, altitude
- FROM ONLY cities
- WHERE altitude > 500;
+ <indexterm>
+ <primary>column</primary>
+ <secondary>removing</secondary>
+ </indexterm>
- name | altitude
------------+----------
- Las Vegas | 2174
- Mariposa | 1953
+ <para>
+ To remove a column, use a command like this:
+<programlisting>
+ALTER TABLE products DROP COLUMN description;
</programlisting>
- </para>
+ Whatever data was in the column disappears. Table constraints involving
+ the column are dropped, too. However, if the column is referenced by a
+ foreign key constraint of another table,
+ <productname>PostgreSQL</productname> will not silently drop that
+ constraint. You can authorize dropping everything that depends on
+ the column by adding <literal>CASCADE</>:
+<programlisting>
+ALTER TABLE products DROP COLUMN description CASCADE;
+</programlisting>
+ See <xref linkend="ddl-depend"> for a description of the general
+ mechanism behind this.
+ </para>
+ </sect2>
- <para>
- Here the <literal>ONLY</literal> keyword indicates that the query
- should apply only to <literal>cities</literal>, and not any tables
- below <literal>cities</literal> in the inheritance hierarchy. Many
- of the commands that we have already discussed —
- <command>SELECT</command>, <command>UPDATE</command> and
- <command>DELETE</command> — support the
- <literal>ONLY</literal> keyword.
- </para>
+ <sect2>
+ <title>Adding a Constraint</title>
- <note>
- <title>Inheritance and Permissions</title>
- <para>
- Because permissions are not inherited automatically, a user
- attempting to access a parent table must either have at least the
- same permission for the child table or must use the
- <quote>ONLY</quote> notation. If creating a new inheritance
- relationship in an existing system be careful that this does not
- create problems.
- </para>
- </note>
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>adding</secondary>
+ </indexterm>
- <para>
- Inheritance does not automatically propagate data from
- <command>INSERT</command> or <command>COPY</command> commands to
- other tables in the inheritance hierarchy. In our example, the
- following <command>INSERT</command> statement will fail:
+ <para>
+ To add a constraint, the table constraint syntax is used. For example:
<programlisting>
-INSERT INTO cities
-(name, population, altitude, state)
-VALUES ('New York', NULL, NULL, 'NY');
+ALTER TABLE products ADD CHECK (name <> '');
+ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);
+ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
</programlisting>
- We might hope that the data would be somehow routed to the
- <literal>capitals</literal> table, though this does not happen. If
- the child has no locally defined columns, then it is possible to
- route data from the parent to the child using a rule, see <xref
- linkend="rules-update">. This is not possible with the above
- <command>INSERT</> statement because the <literal>state</> column
- does not exist on both parent and child tables.
- </para>
-
- <para>
- In some cases you may wish to know which table a particular row
- originated from. There is a system column called
- <structfield>tableoid</structfield> in each table which can tell you the
- originating table:
-
+ To add a not-null constraint, which cannot be written as a table
+ constraint, use this syntax:
<programlisting>
-SELECT c.tableoid, c.name, c.altitude
-FROM cities c
-WHERE c.altitude > 500;
+ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
</programlisting>
+ </para>
- which returns:
+ <para>
+ The constraint will be checked immediately, so the table data must
+ satisfy the constraint before it can be added.
+ </para>
+ </sect2>
-<programlisting>
- tableoid | name | altitude
-----------+-----------+----------
- 139793 | Las Vegas | 2174
- 139793 | Mariposa | 1953
- 139798 | Madison | 845
-</programlisting>
+ <sect2>
+ <title>Removing a Constraint</title>
- (If you try to reproduce this example, you will probably get
- different numeric OIDs.) By doing a join with
- <structname>pg_class</> you can see the actual table names:
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>removing</secondary>
+ </indexterm>
+ <para>
+ To remove a constraint you need to know its name. If you gave it
+ a name then that's easy. Otherwise the system assigned a
+ generated name, which you need to find out. The
+ <application>psql</application> command <literal>\d
+ <replaceable>tablename</replaceable></literal> can be helpful
+ here; other interfaces might also provide a way to inspect table
+ details. Then the command is:
<programlisting>
-SELECT p.relname, c.name, c.altitude
-FROM cities c, pg_class p
-WHERE c.altitude > 500 and c.tableoid = p.oid;
+ALTER TABLE products DROP CONSTRAINT some_name;
</programlisting>
+ (If you are dealing with a generated constraint name like <literal>$2</>,
+ don't forget that you'll need to double-quote it to make it a valid
+ identifier.)
+ </para>
- which returns:
+ <para>
+ As with dropping a column, you need to add <literal>CASCADE</> if you
+ want to drop a constraint that something else depends on. An example
+ is that a foreign key constraint depends on a unique or primary key
+ constraint on the referenced column(s).
+ </para>
+ <para>
+ This works the same for all constraint types except not-null
+ constraints. To drop a not null constraint use
<programlisting>
- relname | name | altitude
-----------+-----------+----------
- cities | Las Vegas | 2174
- cities | Mariposa | 1953
- capitals | Madison | 845
+ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
</programlisting>
- </para>
+ (Recall that not-null constraints do not have names.)
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Changing a Column's Default Value</title>
+
+ <indexterm>
+ <primary>default value</primary>
+ <secondary>changing</secondary>
+ </indexterm>
+
+ <para>
+ To set a new default for a column, use a command like this:
+<programlisting>
+ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
+</programlisting>
+ Note that this doesn't affect any existing rows in the table, it
+ just changes the default for future <command>INSERT</> commands.
+ </para>
+
+ <para>
+ To remove any default value, use
+<programlisting>
+ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
+</programlisting>
+ This is effectively the same as setting the default to null.
+ As a consequence, it is not an error
+ to drop a default where one hadn't been defined, because the
+ default is implicitly the null value.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Changing a Column's Data Type</title>
+
+ <indexterm>
+ <primary>column data type</primary>
+ <secondary>changing</secondary>
+ </indexterm>
+
+ <para>
+ To convert a column to a different data type, use a command like this:
+<programlisting>
+ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
+</programlisting>
+ This will succeed only if each existing entry in the column can be
+ converted to the new type by an implicit cast. If a more complex
+ conversion is needed, you can add a <literal>USING</> clause that
+ specifies how to compute the new values from the old.
+ </para>
+
+ <para>
+ <productname>PostgreSQL</> will attempt to convert the column's
+ default value (if any) to the new type, as well as any constraints
+ that involve the column. But these conversions may fail, or may
+ produce surprising results. It's often best to drop any constraints
+ on the column before altering its type, and then add back suitably
+ modified constraints afterwards.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Renaming a Column</title>
+
+ <indexterm>
+ <primary>column</primary>
+ <secondary>renaming</secondary>
+ </indexterm>
+
+ <para>
+ To rename a column:
+<programlisting>
+ALTER TABLE products RENAME COLUMN product_no TO product_number;
+</programlisting>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Renaming a Table</title>
+
+ <indexterm>
+ <primary>table</primary>
+ <secondary>renaming</secondary>
+ </indexterm>
+
+ <para>
+ To rename a table:
+<programlisting>
+ALTER TABLE products RENAME TO items;
+</programlisting>
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="ddl-priv">
+ <title>Privileges</title>
+
+ <indexterm zone="ddl-priv">
+ <primary>privilege</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>permission</primary>
+ <see>privilege</see>
+ </indexterm>
<para>
- As shown above, a child table may locally define columns as well as
- inheriting them from their parents. However, a locally defined
- column cannot override the data type of an inherited column of the
- same name. A table can inherit from a table that has itself
- inherited from other tables. A table can also inherit from more
- than one parent table, in which case it inherits the union of the
- columns defined by the parent tables. Inherited columns with
- duplicate names and data types will be merged so that only a single
- column is stored.
+ When you create a database object, you become its owner. By
+ default, only the owner of an object can do anything with the
+ object. In order to allow other users to use it,
+ <firstterm>privileges</firstterm> must be granted. (However,
+ users that have the superuser attribute can always
+ access any object.)
</para>
<para>
- Table inheritance can currently only be defined using the <xref
- linkend="sql-createtable" endterm="sql-createtable-title">
- statement. The related statement <literal>CREATE TABLE ... AS
- SELECT</literal> does not allow inheritance to be specified. There
- is no way to add an inheritance link to make an existing table into
- a child table. Similarly, there is no way to remove an inheritance
- link from a child table once it has been defined, other than using
- <literal>DROP TABLE</literal>. A parent table cannot be dropped
- while any of its children remain. If you wish to remove a table and
- all of its descendants, then you can do so using the
- <literal>CASCADE</literal> option of the <xref
- linkend="sql-droptable" endterm="sql-droptable-title"> statement.
+ There are several different privileges: <literal>SELECT</>,
+ <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
+ <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
+ <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>, and
+ <literal>USAGE</>. The privileges applicable to a particular
+ object vary depending on the object's type (table, function, etc).
+ For complete information on the different types of privileges
+ supported by <productname>PostgreSQL</productname>, refer to the
+ <xref linkend="sql-grant" endterm="sql-grant-title"> reference
+ page. The following sections and chapters will also show you how
+ those privileges are used.
</para>
<para>
- Check constraints can be defined on tables within an inheritance
- hierarchy. All check constraints on a parent table are
- automatically inherited by all of their children. It is currently
- possible to inherit mutually exclusive check constraints, but that
- definition quickly shows itself since all attempted row inserts
- will be rejected.
+ The right to modify or destroy an object is always the privilege of
+ the owner only.
</para>
+ <note>
+ <para>
+ To change the owner of a table, index, sequence, or view, use the
+ <xref linkend="sql-altertable" endterm="sql-altertable-title">
+ command. There are corresponding <literal>ALTER</> commands for
+ other object types.
+ </para>
+ </note>
+
<para>
- <xref linkend="sql-altertable" endterm="sql-altertable-title"> will
- propogate any changes in data definition on columns or check
- constraints down the inheritance hierarchy. Again, dropping
- columns or constraints on parent tables is only possible when using
- the <literal>CASCADE</literal> option. <command>ALTER
- TABLE</command> follows the same rules for duplicate column merging
- and rejection that apply during <command>CREATE TABLE</command>.
+ To assign privileges, the <command>GRANT</command> command is
+ used. For example, if <literal>joe</literal> is an existing user, and
+ <literal>accounts</literal> is an existing table, the privilege to
+ update the table can be granted with
+<programlisting>
+GRANT UPDATE ON accounts TO joe;
+</programlisting>
+ To grant a privilege to a group, use this syntax:
+<programlisting>
+GRANT SELECT ON accounts TO GROUP staff;
+</programlisting>
+ The special <quote>user</quote> name <literal>PUBLIC</literal> can
+ be used to grant a privilege to every user on the system. Writing
+ <literal>ALL</literal> in place of a specific privilege grants all
+ privileges that are relevant for the object type.
+ </para>
+
+ <para>
+ To revoke a privilege, use the fittingly named
+ <command>REVOKE</command> command:
+<programlisting>
+REVOKE ALL ON accounts FROM PUBLIC;
+</programlisting>
+ The special privileges of the object owner (i.e., the right to do
+ <command>DROP</>, <command>GRANT</>, <command>REVOKE</>, etc.)
+ are always implicit in being the owner,
+ and cannot be granted or revoked. But the object owner can choose
+ to revoke his own ordinary privileges, for example to make a
+ table read-only for himself as well as others.
+ </para>
+
+ <para>
+ Ordinarily, only the object's owner (or a superuser) can grant or
+ revoke privileges on an object. However, it is possible to grant a
+ privilege <quote>with grant option</>, which gives the recipient
+ the right to grant it in turn to others. If the grant option is
+ subsequently revoked then all who received the privilege from that
+ recipient (directly or through a chain of grants) will lose the
+ privilege. For details see the <xref linkend="sql-grant"
+ endterm="sql-grant-title"> and <xref linkend="sql-revoke"
+ endterm="sql-revoke-title"> reference pages.
+ </para>
+ </sect1>
+
+ <sect1 id="ddl-schemas">
+ <title>Schemas</title>
+
+ <indexterm zone="ddl-schemas">
+ <primary>schema</primary>
+ </indexterm>
+
+ <para>
+ A <productname>PostgreSQL</productname> database cluster
+ contains one or more named databases. Users and groups of users are
+ shared across the entire cluster, but no other data is shared across
+ databases. Any given client connection to the server can access
+ only the data in a single database, the one specified in the connection
+ request.
+ </para>
+
+ <note>
+ <para>
+ Users of a cluster do not necessarily have the privilege to access every
+ database in the cluster. Sharing of user names means that there
+ cannot be different users named, say, <literal>joe</> in two databases
+ in the same cluster; but the system can be configured to allow
+ <literal>joe</> access to only some of the databases.
+ </para>
+ </note>
+
+ <para>
+ A database contains one or more named <firstterm>schemas</>, which
+ in turn contain tables. Schemas also contain other kinds of named
+ objects, including data types, functions, and operators. The same
+ object name can be used in different schemas without conflict; for
+ example, both <literal>schema1</> and <literal>myschema</> may
+ contain tables named <literal>mytable</>. Unlike databases,
+ schemas are not rigidly separated: a user may access objects in any
+ of the schemas in the database he is connected to, if he has
+ privileges to do so.
</para>
<para>
- Both parent and child tables can have primary and foreign keys, so
- that they can take part normally on both the referencing and
- referenced sides of a foreign key constraint. Indexes may be
- defined on any of these columns whether or not they are inherited.
- However, a serious current limitation of the inheritance feature is
- that indexes (including unique constraints) and foreign key
- constraints only apply to single tables and do not also index their
- inheritance children. This is true on both sides of a foreign key
- constraint. Thus, in the terms of the above example:
+ There are several reasons why one might want to use schemas:
<itemizedlist>
<listitem>
<para>
- If we declared <structname>cities</>.<structfield>name</> to be
- <literal>UNIQUE</> or a <literal>PRIMARY KEY</>, this would not stop the
- <structname>capitals</> table from having rows with names duplicating
- rows in <structname>cities</>. And those duplicate rows would by
- default show up in queries from <structname>cities</>. In fact, by
- default <structname>capitals</> would have no unique constraint at all,
- and so could contain multiple rows with the same name.
- You could add a unique constraint to <structname>capitals</>, but this
- would not prevent duplication compared to <structname>cities</>.
+ To allow many users to use one database without interfering with
+ each other.
</para>
</listitem>
<listitem>
<para>
- Similarly, if we were to specify that
- <structname>cities</>.<structfield>name</> <literal>REFERENCES</> some
- other table, this constraint would not automatically propagate to
- <structname>capitals</>. However, it is possible to set up a
- foreign key such as <structname>capitals</>.<structfield>name</>
- <literal>REFERENCES</> <structname>states</>.<structfield>name</>.
- So it is possible to workaround this restriction by manually adding
- foreign keys to each child table.
+ To organize database objects into logical groups to make them
+ more manageable.
</para>
</listitem>
<listitem>
<para>
- Specifying that another table's column <literal>REFERENCES
- cities(name)</> would allow the other table to contain city names, but
- not capital names. There is no good workaround for this case.
+ Third-party applications can be put into separate schemas so
+ they cannot collide with the names of other objects.
</para>
</listitem>
</itemizedlist>
- These deficiencies will probably be fixed in some future release,
- but in the meantime considerable care is needed in deciding whether
- inheritance is useful for your problem.
-
+ Schemas are analogous to directories at the operating system level,
+ except that schemas cannot be nested.
</para>
- <note>
- <title>Deprecated</title>
+ <sect2 id="ddl-schemas-create">
+ <title>Creating a Schema</title>
+
+ <indexterm zone="ddl-schemas-create">
+ <primary>schema</primary>
+ <secondary>creating</secondary>
+ </indexterm>
+
<para>
- In previous versions of <productname>PostgreSQL</productname>, the
- default behavior was not to include child tables in queries. This was
- found to be error prone and is also in violation of the SQL
- standard. Under the old syntax, to get the sub-tables you append
- <literal>*</literal> to the table name. For example:
+ To create a schema, use the command <command>CREATE
+ SCHEMA</command>. Give the schema a name of your choice. For
+ example:
<programlisting>
-SELECT * from cities*;
+CREATE SCHEMA myschema;
</programlisting>
- You can still explicitly specify scanning child tables by
- appending <literal>*</literal>, as well as explicitly specify not
- scanning child tables by writing <quote>ONLY</quote>. But
- beginning in version 7.1, the default behavior for an undecorated
- table name is to scan its child tables too, whereas before the
- default was not to do so. To get the old default behavior,
- disable the <xref linkend="guc-sql-inheritance"> configuration
- option.
</para>
- </note>
-
- </sect1>
-
- <sect1 id="ce-partitioning">
- <title>Constraint Exclusion and Partitioning</title>
<indexterm>
- <primary>partitioning</primary>
+ <primary>qualified name</primary>
</indexterm>
<indexterm>
- <primary>constraint exclusion</primary>
+ <primary>name</primary>
+ <secondary>qualified</secondary>
</indexterm>
<para>
- <productname>PostgreSQL</productname> supports basic table
- partitioning. This section describes why and how you can implement
- this as part of your database design.
+ To create or access objects in a schema, write a
+ <firstterm>qualified name</> consisting of the schema name and
+ table name separated by a dot:
+<synopsis>
+<replaceable>schema</><literal>.</><replaceable>table</>
+</synopsis>
+ This works anywhere a table name is expected, including the table
+ modification commands and the data access commands discussed in
+ the following chapters.
+ (For brevity we will speak of tables only, but the same ideas apply
+ to other kinds of named objects, such as types and functions.)
</para>
- <sect2 id="ce-partitioning-overview">
- <title>Overview</title>
-
<para>
- Currently, partitioning is implemented in conjunction with table
- inheritance only, though using fully SQL compliant syntax.
- Table inheritance allows tables to be split into partitions, and
- constraint exclusion allows partitions to be selectively combined
- as needed to satisfy a particular <command>SELECT</command>
- statement. You should be familiar with inheritance (see <xref
- linkend="ddl-inherit">) before attempting to implement
- partitioning.
+ Actually, the even more general syntax
+<synopsis>
+<replaceable>database</><literal>.</><replaceable>schema</><literal>.</><replaceable>table</>
+</synopsis>
+ can be used too, but at present this is just for <foreignphrase>pro
+ forma</> compliance with the SQL standard. If you write a database name,
+ it must be the same as the database you are connected to.
</para>
<para>
- Partitioning can provide several benefits:
- <itemizedlist>
- <listitem>
- <para>
- Query performance can be improved dramatically for certain kinds
- of queries without the need to maintain costly indexes.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Insert performance can be improved by breaking down a large
- index into multiple pieces. When an index no longer fits easily
- in memory, both read and write operations on the index take
- progressively more disk accesses.
- </para>
- </listitem>
+ So to create a table in the new schema, use
+<programlisting>
+CREATE TABLE myschema.mytable (
+ ...
+);
+</programlisting>
+ </para>
- <listitem>
- <para>
- Bulk deletes may be avoided altogether by simply removing one of the
- partitions, if that requirement is planned into the partitioning design.
- </para>
- </listitem>
+ <indexterm>
+ <primary>schema</primary>
+ <secondary>removing</secondary>
+ </indexterm>
- <listitem>
- <para>
- Seldom-used data can be migrated to cheaper and slower storage media.
- </para>
- </listitem>
- </itemizedlist>
+ <para>
+ To drop a schema if it's empty (all objects in it have been
+ dropped), use
+<programlisting>
+DROP SCHEMA myschema;
+</programlisting>
+ To drop a schema including all contained objects, use
+<programlisting>
+DROP SCHEMA myschema CASCADE;
+</programlisting>
+ See <xref linkend="ddl-depend"> for a description of the general
+ mechanism behind this.
+ </para>
- The benefits will normally be worthwhile only when a table would
- otherwise be very large. The exact point at which a table will
- benefit from partitioning depends on the application, although the
- size of the table should usually exceed the physical memory of the
- database server.
+ <para>
+ Often you will want to create a schema owned by someone else
+ (since this is one of the ways to restrict the activities of your
+ users to well-defined namespaces). The syntax for that is:
+<programlisting>
+CREATE SCHEMA <replaceable>schemaname</replaceable> AUTHORIZATION <replaceable>username</replaceable>;
+</programlisting>
+ You can even omit the schema name, in which case the schema name
+ will be the same as the user name. See <xref
+ linkend="ddl-schemas-patterns"> for how this can be useful.
</para>
<para>
- The following partitioning types are supported by
- <productname>PostgreSQL</productname> &version;:
+ Schema names beginning with <literal>pg_</> are reserved for
+ system purposes and may not be created by users.
+ </para>
+ </sect2>
- <variablelist>
- <varlistentry>
- <term>Range Partitioning</term>
+ <sect2 id="ddl-schemas-public">
+ <title>The Public Schema</title>
- <listitem>
- <para>
- The table is partitioned along a <quote>range</quote> defined
- by a single column or set of columns, with no overlap between
- partitions. Examples might be a date range or a range of
- identifiers for particular business objects.
- </para>
- </listitem>
- </varlistentry>
+ <indexterm zone="ddl-schemas-public">
+ <primary>schema</primary>
+ <secondary>public</secondary>
+ </indexterm>
- <varlistentry>
- <term>List Partitioning</term>
+ <para>
+ In the previous sections we created tables without specifying any
+ schema names. By default, such tables (and other objects) are
+ automatically put into a schema named <quote>public</quote>. Every new
+ database contains such a schema. Thus, the following are equivalent:
+<programlisting>
+CREATE TABLE products ( ... );
+</programlisting>
+ and
+<programlisting>
+CREATE TABLE public.products ( ... );
+</programlisting>
+ </para>
+ </sect2>
- <listitem>
- <para>
- The table is partitioned by explicitly listing which values
- relate to each partition.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
+ <sect2 id="ddl-schemas-path">
+ <title>The Schema Search Path</title>
- Hash partitioning is not currently supported.
- </para>
- </sect2>
+ <indexterm>
+ <primary>search path</primary>
+ </indexterm>
- <sect2 id="ce-partitioning-implementation">
- <title>Implementing Partitioning</title>
+ <indexterm>
+ <primary>unqualified name</primary>
+ </indexterm>
- <para>
- Partitioning a table is a straightforward process. There
- are a wide range of options for you to consider, so judging exactly
- when and how to implement partitioning is a more complex topic. We
- will address that complexity primarily through the examples in this
- section.
- </para>
+ <indexterm>
+ <primary>name</primary>
+ <secondary>unqualified</secondary>
+ </indexterm>
- <para>
- To use partitioning, do the following:
- <orderedlist spacing=compact>
- <listitem>
- <para>
- Create the <quote>master</quote> table, from which all of the
- partitions will inherit.
- </para>
- <para>
- This table will contain no data. Do not define any
- constraints or keys on this table, unless you intend them to
- be applied equally to all partitions.
- </para>
- </listitem>
+ <para>
+ Qualified names are tedious to write, and it's often best not to
+ wire a particular schema name into applications anyway. Therefore
+ tables are often referred to by <firstterm>unqualified names</>,
+ which consist of just the table name. The system determines which table
+ is meant by following a <firstterm>search path</>, which is a list
+ of schemas to look in. The first matching table in the search path
+ is taken to be the one wanted. If there is no match in the search
+ path, an error is reported, even if matching table names exist
+ in other schemas in the database.
+ </para>
- <listitem>
- <para>
- Create several <quote>child</quote> tables that inherit from
- the master table.
- </para>
+ <indexterm>
+ <primary>schema</primary>
+ <secondary>current</secondary>
+ </indexterm>
- <para>
- We will refer to the child tables as partitions, though they
- are in every way normal <productname>PostgreSQL</> tables.
- </para>
- </listitem>
+ <para>
+ The first schema named in the search path is called the current schema.
+ Aside from being the first schema searched, it is also the schema in
+ which new tables will be created if the <command>CREATE TABLE</>
+ command does not specify a schema name.
+ </para>
- <listitem>
- <para>
- Add table constraints to define the allowed values in each partition.
- </para>
- <para>
- Only clauses of the form [COLUMN] [OPERATOR] [CONSTANT(s)] will be used
- for constraint exclusion. Simple examples would be:
+ <indexterm>
+ <primary>search_path</primary>
+ </indexterm>
+
+ <para>
+ To show the current search path, use the following command:
<programlisting>
-CHECK ( x = 1 )
-CHECK ( county IN ( 'Oxfordshire','Buckinghamshire','Warwickshire' ))
-CHECK ( outletID BETWEEN 1 AND 99 )
+SHOW search_path;
</programlisting>
+ In the default setup this returns:
+<screen>
+ search_path
+--------------
+ $user,public
+</screen>
+ The first element specifies that a schema with the same name as
+ the current user is to be searched. If no such schema exists,
+ the entry is ignored. The second element refers to the
+ public schema that we have seen already.
+ </para>
- These can be linked together with the Boolean operators
- <literal>AND</literal> and <literal>OR</literal> to form
- complex constraints. Note that there is no difference in
- syntax between range and list partitioning; those terms are
- descriptive only. Ensure that the set of values in each child
- table do not overlap.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Add any other indexes you want to the partitions, bearing in
- mind that it is always more efficient to add indexes after
- data has been bulk loaded.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Optionally, define a rule or trigger to redirect modifications
- of the master table to the appropriate partition.
- </para>
- </listitem>
-
- </orderedlist>
- </para>
-
- <para>
- For example, suppose we are constructing a database for a large
- ice cream company. The company measures peak temperatures every
- day as well as ice cream sales in each region. They have two
- tables:
-
-<programlisting>
-CREATE TABLE cities (
- id int not null,
- name text not null,
- altitude int -- in feet
-);
-
-CREATE TABLE measurement (
- city_id int not null,
- logdate date not null,
- peaktemp int,
- unitsales int
-);
-</programlisting>
-
- To reduce the amount of old data that needs to be stored, we
- decide to only keep the most recent 3 years worth of data. At the
- beginning of each month we remove the oldest month's data.
- </para>
-
- <para>
- Most queries just access the last week, month or quarter's data,
- since we need to keep track of sales. As a result we have a large table,
- yet only the most frequent 10% is accessed. Most of these queries
- are online reports for various levels of management. These queries access
- much of the table, so it is difficult to build enough indexes and at
- the same time allow us to keep loading all of the data fast enough.
- Yet, the reports are online so we need to respond quickly.
- </para>
-
- <para>
- In this situation we can use partitioning to help us meet all of our
- different requirements for the measurements table. Following the
- steps outlined above, partitioning can be enabled as follows:
- </para>
-
- <para>
- <orderedlist spacing=compact>
- <listitem>
- <para>
- The measurement table is our master table.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Next we create one partition for each month using inheritance:
-
-<programlisting>
-CREATE TABLE measurement_yy04mm02 ( ) INHERITS (measurement);
-CREATE TABLE measurement_yy04mm03 ( ) INHERITS (measurement);
-...
-CREATE TABLE measurement_yy05mm11 ( ) INHERITS (measurement);
-CREATE TABLE measurement_yy05mm12 ( ) INHERITS (measurement);
-CREATE TABLE measurement_yy06mm01 ( ) INHERITS (measurement);
-</programlisting>
-
- Each of the partitions are complete tables in their own right,
- but they inherit their definition from the measurement table.
- </para>
-
- <para>
- This solves one of our problems: deleting old data. Each
- month, all we need to do is perform a <command>DROP
- TABLE</command> on the oldest table and create a new table to
- insert into.
- </para>
- </listitem>
-
- <listitem>
- <para>
- We now add non-overlapping table constraints, so that our
- table creation script becomes:
-
- <programlisting>
-CREATE TABLE measurement_yy04mm02 (
- CHECK ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
- ) INHERITS (measurement);
-CREATE TABLE measurement_yy04mm03 (
- CHECK ( logdate >= DATE '2004-03-01' AND logdate < DATE '2004-04-01' )
- ) INHERITS (measurement);
-...
-CREATE TABLE measurement_yy05mm11 (
- CHECK ( logdate >= DATE '2005-11-01' AND logdate < DATE '2005-12-01' )
- ) INHERITS (measurement);
-CREATE TABLE measurement_yy05mm12 (
- CHECK ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
- ) INHERITS (measurement);
-CREATE TABLE measurement_yy06mm01 (
- CHECK ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
- ) INHERITS (measurement);
-</programlisting>
- </para>
- </listitem>
-
- <listitem>
- <para>
- We choose not to add further indexes at this time.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Data will be added each day to the latest partition. This
- allows us to set up a very simple rule to insert data. We must
- redefine this each month so that it always points to the
- current partition.
-
-<programlisting>
-CREATE OR REPLACE RULE measurement_current_partition AS
-ON INSERT
-TO measurement
-DO INSTEAD
- INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
- NEW.logdate,
- NEW.peaktemp,
- NEW.unitsales );
-</programlisting>
-
- We might want to insert data and have the server automatically
- locate the partition into which the row should be added. We
- could do this with a more complex set of rules as shown below.
-
-<programlisting>
-CREATE RULE measurement_insert_yy04mm02 AS
-ON INSERT
-TO measurement WHERE
- ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
-DO INSTEAD
- INSERT INTO measurement_yy04mm02 VALUES ( NEW.city_id,
- NEW.logdate,
- NEW.peaktemp,
- NEW.unitsales );
-...
-CREATE RULE measurement_insert_yy05mm12 AS
-ON INSERT
-TO measurement WHERE
- ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
-DO INSTEAD
- INSERT INTO measurement_yy05mm12 VALUES ( NEW.city_id,
- NEW.logdate,
- NEW.peaktemp,
- NEW.unitsales );
-CREATE RULE measurement_insert_yy06mm01 AS
-ON INSERT
-TO measurement WHERE
- ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
-DO INSTEAD
- INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
- NEW.logdate,
- NEW.peaktemp,
- NEW.unitsales );
-</programlisting>
-
- Note that the <literal>WHERE</literal> clause in each rule
- exactly matches those used for the <literal>CHECK</literal>
- constraints on each partition.
- </para>
- </listitem>
- </orderedlist>
- </para>
-
- <para>
- As we can see, a complex partitioning scheme could require a
- substantial amount of DDL. In the above example we would be
- creating a new partition each month, so it may be wise to write a
- script that generates the required DDL automatically.
- </para>
-
- <para>
- The following caveats apply:
- <itemizedlist>
- <listitem>
- <para>
- There is currently no way to specify that all of the
- <literal>CHECK</literal> constraints are mutually
- exclusive. Care is required by the database designer.
- </para>
- </listitem>
-
- <listitem>
- <para>
- There is currently no way to specify that rows may not be
- inserted into the master table. A <literal>CHECK</literal>
- constraint on the master table will be inherited by all child
- tables, so that cannot not be used for this purpose.
- </para>
- </listitem>
-
- <listitem>
- <para>
- For some data types you must explicitly coerce the constant
- values into the data type of the column. The following constraint
- will work if <varname>x</varname> is an <type>integer</type>
- data type, but not if <varname>x</varname> is a
- <type>bigint</type>:
-<programlisting>
-CHECK ( x = 1 )
-</programlisting>
- For <type>bigint</type> we must use a constraint like:
-<programlisting>
-CHECK ( x = 1::bigint )
-</programlisting>
- The problem is not limited to the <type>bigint</type> data type
- — it can occur whenever the default data type of the
- constant does not match the data type of the column to which it
- is being compared.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Partitioning can also be arranged using a <literal>UNION
- ALL</literal> view:
-
-<programlisting>
-CREATE VIEW measurement AS
- SELECT * FROM measurement_yy04mm02
-UNION ALL SELECT * FROM measurement_yy04mm03
-...
-UNION ALL SELECT * FROM measurement_yy05mm11
-UNION ALL SELECT * FROM measurement_yy05mm12
-UNION ALL SELECT * FROM measurement_yy06mm01;
-</programlisting>
-
- However, constraint exclusion is currently not supported for
- partitioned tables defined in this manner.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </sect2>
-
- <sect2 id="constraint-exclusion-queries">
- <title>Constraint Exclusion in Queries</title>
-
- <para>
- Partitioning can be used to improve query performance when used in
- conjunction with constraint exclusion. As an example:
-
-<programlisting>
-SET constraint_exclusion=true;
-SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
-</programlisting>
-
- Without constraint exclusion, the above query would scan each of
- the partitions of the measurement table. With constraint
- exclusion, the planner will examine each of the constraints and
- try to prove that each of the partitions needs to be involved in
- the query. If the planner is able to refute that for any
- partition, it excludes the partition from the query plan.
- </para>
+ <para>
+ The first schema in the search path that exists is the default
+ location for creating new objects. That is the reason that by
+ default objects are created in the public schema. When objects
+ are referenced in any other context without schema qualification
+ (table modification, data modification, or query commands) the
+ search path is traversed until a matching object is found.
+ Therefore, in the default configuration, any unqualified access
+ again can only refer to the public schema.
+ </para>
<para>
- You can use the <command>EXPLAIN</> command to show the difference
- between a plan with <varname>constraint_exclusion</> on and a plan
- with it off.
-
-<programlisting>
-SET constraint_exclusion=false;
-EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
-
- QUERY PLAN
------------------------------------------------------------------------------------------------
- Aggregate (cost=158.66..158.68 rows=1 width=0)
- -> Append (cost=0.00..151.88 rows=2715 width=0)
- -> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
- -> Seq Scan on measurement_yy04mm02 measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
- -> Seq Scan on measurement_yy04mm03 measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
-...
- -> Seq Scan on measurement_yy05mm12 measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
- -> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
-</programlisting>
-
- Now when we enable constraint exclusion, we get a significantly
- reduced plan but the same result set:
-
-<programlisting>
-SET constraint_exclusion=true;
-EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
- QUERY PLAN
------------------------------------------------------------------------------------------------
- Aggregate (cost=63.47..63.48 rows=1 width=0)
- -> Append (cost=0.00..60.75 rows=1086 width=0)
- -> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
- -> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0)
- Filter: (logdate >= '2006-01-01'::date)
-</programlisting>
-
- Don't forget that you still need to run <command>ANALYZE</command>
- on each partition individually. A command like this
+ To put our new schema in the path, we use
<programlisting>
-ANALYZE measurement;
+SET search_path TO myschema,public;
</programlisting>
-
- only affects the master table.
- </para>
-
- <para>
- No indexes are required to use constraint exclusion. The
- partitions should be defined with appropriate <literal>CHECK</>
- constraints. These are then compared with the predicates of the
- <command>SELECT</> query to determine which partitions must be
- scanned.
- </para>
-
- <para>
- The following caveats apply to this release:
- <itemizedlist>
- <listitem>
- <para>
- Constraint exclusion only works when the query directly matches
- a constant. A constant bound to a parameterized query will not
- work in the same way since the plan is fixed and would need to
- vary with each execution. Also, stable constants such as
- <literal>CURRENT_DATE</literal> may not be used, since these are
- constant only for during the execution of a single query. Join
- conditions will not allow constraint exclusion to work either.
- </para>
- </listitem>
-
- <listitem>
- <para>
- <command>UPDATE</command> and <command>DELETE</command> commands
- against the master table do not perform constraint exclusion.
- </para>
- </listitem>
-
- <listitem>
- <para>
- All constraints on all partitions of the master table are considered for
- constraint exclusion, so large numbers of partitions are likely to
- increase query planning time considerably.
- </para>
- </listitem>
-
- </itemizedlist>
+ (We omit the <literal>$user</literal> here because we have no
+ immediate need for it.) And then we can access the table without
+ schema qualification:
+<programlisting>
+DROP TABLE mytable;
+</programlisting>
+ Also, since <literal>myschema</literal> is the first element in
+ the path, new objects would by default be created in it.
</para>
- </sect2>
-
- </sect1>
-
- <sect1 id="ddl-alter">
- <title>Modifying Tables</title>
-
- <indexterm zone="ddl-alter">
- <primary>table</primary>
- <secondary>modifying</secondary>
- </indexterm>
-
- <para>
- When you create a table and you realize that you made a mistake, or
- the requirements of the application change, then you can drop the
- table and create it again. But this is not a convenient option if
- the table is already filled with data, or if the table is
- referenced by other database objects (for instance a foreign key
- constraint). Therefore <productname>PostgreSQL</productname>
- provides a family of commands to make modifications to existing
- tables. Note that this is conceptually distinct from altering
- the data contained in the table: here we are interested in altering
- the definition, or structure, of the table.
- </para>
-
- <para>
- You can
- <itemizedlist spacing="compact">
- <listitem>
- <para>Add columns,</para>
- </listitem>
- <listitem>
- <para>Remove columns,</para>
- </listitem>
- <listitem>
- <para>Add constraints,</para>
- </listitem>
- <listitem>
- <para>Remove constraints,</para>
- </listitem>
- <listitem>
- <para>Change default values,</para>
- </listitem>
- <listitem>
- <para>Change column data types,</para>
- </listitem>
- <listitem>
- <para>Rename columns,</para>
- </listitem>
- <listitem>
- <para>Rename tables.</para>
- </listitem>
- </itemizedlist>
-
- All these actions are performed using the
- <xref linkend="sql-altertable" endterm="sql-altertable-title">
- command.
- </para>
-
- <sect2>
- <title>Adding a Column</title>
-
- <indexterm>
- <primary>column</primary>
- <secondary>adding</secondary>
- </indexterm>
-
<para>
- To add a column, use a command like this:
+ We could also have written
<programlisting>
-ALTER TABLE products ADD COLUMN description text;
+SET search_path TO myschema;
</programlisting>
- The new column is initially filled with whatever default
- value is given (null if you don't specify a <literal>DEFAULT</> clause).
+ Then we no longer have access to the public schema without
+ explicit qualification. There is nothing special about the public
+ schema except that it exists by default. It can be dropped, too.
</para>
<para>
- You can also define constraints on the column at the same time,
- using the usual syntax:
+ See also <xref linkend="functions-info"> for other ways to manipulate
+ the schema search path.
+ </para>
+
+ <para>
+ The search path works in the same way for data type names, function names,
+ and operator names as it does for table names. Data type and function
+ names can be qualified in exactly the same way as table names. If you
+ need to write a qualified operator name in an expression, there is a
+ special provision: you must write
+<synopsis>
+<literal>OPERATOR(</><replaceable>schema</><literal>.</><replaceable>operator</><literal>)</>
+</synopsis>
+ This is needed to avoid syntactic ambiguity. An example is
<programlisting>
-ALTER TABLE products ADD COLUMN description text CHECK (description <> '');
+SELECT 3 OPERATOR(pg_catalog.+) 4;
</programlisting>
- In fact all the options that can be applied to a column description
- in <command>CREATE TABLE</> can be used here. Keep in mind however
- that the default value must satisfy the given constraints, or the
- <literal>ADD</> will fail. Alternatively, you can add
- constraints later (see below) after you've filled in the new column
- correctly.
+ In practice one usually relies on the search path for operators,
+ so as not to have to write anything so ugly as that.
</para>
</sect2>
- <sect2>
- <title>Removing a Column</title>
+ <sect2 id="ddl-schemas-priv">
+ <title>Schemas and Privileges</title>
- <indexterm>
- <primary>column</primary>
- <secondary>removing</secondary>
+ <indexterm zone="ddl-schemas-priv">
+ <primary>privilege</primary>
+ <secondary sortas="schemas">for schemas</secondary>
</indexterm>
<para>
- To remove a column, use a command like this:
-<programlisting>
-ALTER TABLE products DROP COLUMN description;
-</programlisting>
- Whatever data was in the column disappears. Table constraints involving
- the column are dropped, too. However, if the column is referenced by a
- foreign key constraint of another table,
- <productname>PostgreSQL</productname> will not silently drop that
- constraint. You can authorize dropping everything that depends on
- the column by adding <literal>CASCADE</>:
+ By default, users cannot access any objects in schemas they do not
+ own. To allow that, the owner of the schema needs to grant the
+ <literal>USAGE</literal> privilege on the schema. To allow users
+ to make use of the objects in the schema, additional privileges
+ may need to be granted, as appropriate for the object.
+ </para>
+
+ <para>
+ A user can also be allowed to create objects in someone else's
+ schema. To allow that, the <literal>CREATE</literal> privilege on
+ the schema needs to be granted. Note that by default, everyone
+ has <literal>CREATE</literal> and <literal>USAGE</literal> privileges on
+ the schema
+ <literal>public</literal>. This allows all users that are able to
+ connect to a given database to create objects in its
+ <literal>public</literal> schema. If you do
+ not want to allow that, you can revoke that privilege:
<programlisting>
-ALTER TABLE products DROP COLUMN description CASCADE;
+REVOKE CREATE ON SCHEMA public FROM PUBLIC;
</programlisting>
- See <xref linkend="ddl-depend"> for a description of the general
- mechanism behind this.
+ (The first <quote>public</quote> is the schema, the second
+ <quote>public</quote> means <quote>every user</quote>. In the
+ first sense it is an identifier, in the second sense it is a
+ key word, hence the different capitalization; recall the
+ guidelines from <xref linkend="sql-syntax-identifiers">.)
</para>
</sect2>
- <sect2>
- <title>Adding a Constraint</title>
+ <sect2 id="ddl-schemas-catalog">
+ <title>The System Catalog Schema</title>
- <indexterm>
- <primary>constraint</primary>
- <secondary>adding</secondary>
+ <indexterm zone="ddl-schemas-catalog">
+ <primary>system catalog</primary>
+ <secondary>schema</secondary>
</indexterm>
<para>
- To add a constraint, the table constraint syntax is used. For example:
-<programlisting>
-ALTER TABLE products ADD CHECK (name <> '');
-ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);
-ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
-</programlisting>
- To add a not-null constraint, which cannot be written as a table
- constraint, use this syntax:
-<programlisting>
-ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
-</programlisting>
+ In addition to <literal>public</> and user-created schemas, each
+ database contains a <literal>pg_catalog</> schema, which contains
+ the system tables and all the built-in data types, functions, and
+ operators. <literal>pg_catalog</> is always effectively part of
+ the search path. If it is not named explicitly in the path then
+ it is implicitly searched <emphasis>before</> searching the path's
+ schemas. This ensures that built-in names will always be
+ findable. However, you may explicitly place
+ <literal>pg_catalog</> at the end of your search path if you
+ prefer to have user-defined names override built-in names.
</para>
<para>
- The constraint will be checked immediately, so the table data must
- satisfy the constraint before it can be added.
+ In <productname>PostgreSQL</productname> versions before 7.3,
+ table names beginning with <literal>pg_</> were reserved. This is
+ no longer true: you may create such a table name if you wish, in
+ any non-system schema. However, it's best to continue to avoid
+ such names, to ensure that you won't suffer a conflict if some
+ future version defines a system table named the same as your
+ table. (With the default search path, an unqualified reference to
+ your table name would be resolved as the system table instead.)
+ System tables will continue to follow the convention of having
+ names beginning with <literal>pg_</>, so that they will not
+ conflict with unqualified user-table names so long as users avoid
+ the <literal>pg_</> prefix.
</para>
</sect2>
- <sect2>
- <title>Removing a Constraint</title>
+ <sect2 id="ddl-schemas-patterns">
+ <title>Usage Patterns</title>
- <indexterm>
- <primary>constraint</primary>
- <secondary>removing</secondary>
- </indexterm>
+ <para>
+ Schemas can be used to organize your data in many ways. There are
+ a few usage patterns that are recommended and are easily supported by
+ the default configuration:
+ <itemizedlist>
+ <listitem>
+ <para>
+ If you do not create any schemas then all users access the
+ public schema implicitly. This simulates the situation where
+ schemas are not available at all. This setup is mainly
+ recommended when there is only a single user or a few cooperating
+ users in a database. This setup also allows smooth transition
+ from the non-schema-aware world.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You can create a schema for each user with the same name as
+ that user. Recall that the default search path starts with
+ <literal>$user</literal>, which resolves to the user name.
+ Therefore, if each user has a separate schema, they access their
+ own schemas by default.
+ </para>
+
+ <para>
+ If you use this setup then you might also want to revoke access
+ to the public schema (or drop it altogether), so users are
+ truly constrained to their own schemas.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To install shared applications (tables to be used by everyone,
+ additional functions provided by third parties, etc.), put them
+ into separate schemas. Remember to grant appropriate
+ privileges to allow the other users to access them. Users can
+ then refer to these additional objects by qualifying the names
+ with a schema name, or they can put the additional schemas into
+ their search path, as they choose.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+ <sect2 id="ddl-schemas-portability">
+ <title>Portability</title>
<para>
- To remove a constraint you need to know its name. If you gave it
- a name then that's easy. Otherwise the system assigned a
- generated name, which you need to find out. The
- <application>psql</application> command <literal>\d
- <replaceable>tablename</replaceable></literal> can be helpful
- here; other interfaces might also provide a way to inspect table
- details. Then the command is:
-<programlisting>
-ALTER TABLE products DROP CONSTRAINT some_name;
-</programlisting>
- (If you are dealing with a generated constraint name like <literal>$2</>,
- don't forget that you'll need to double-quote it to make it a valid
- identifier.)
+ In the SQL standard, the notion of objects in the same schema
+ being owned by different users does not exist. Moreover, some
+ implementations do not allow you to create schemas that have a
+ different name than their owner. In fact, the concepts of schema
+ and user are nearly equivalent in a database system that
+ implements only the basic schema support specified in the
+ standard. Therefore, many users consider qualified names to
+ really consist of
+ <literal><replaceable>username</>.<replaceable>tablename</></literal>.
+ This is how <productname>PostgreSQL</productname> will effectively
+ behave if you create a per-user schema for every user.
</para>
<para>
- As with dropping a column, you need to add <literal>CASCADE</> if you
- want to drop a constraint that something else depends on. An example
- is that a foreign key constraint depends on a unique or primary key
- constraint on the referenced column(s).
+ Also, there is no concept of a <literal>public</> schema in the
+ SQL standard. For maximum conformance to the standard, you should
+ not use (perhaps even remove) the <literal>public</> schema.
</para>
<para>
- This works the same for all constraint types except not-null
- constraints. To drop a not null constraint use
-<programlisting>
-ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
-</programlisting>
- (Recall that not-null constraints do not have names.)
+ Of course, some SQL database systems might not implement schemas
+ at all, or provide namespace support by allowing (possibly
+ limited) cross-database access. If you need to work with those
+ systems, then maximum portability would be achieved by not using
+ schemas at all.
</para>
</sect2>
+ </sect1>
- <sect2>
- <title>Changing a Column's Default Value</title>
-
- <indexterm>
- <primary>default value</primary>
- <secondary>changing</secondary>
- </indexterm>
+ <sect1 id="ddl-inherit">
+ <title>Inheritance</title>
- <para>
- To set a new default for a column, use a command like this:
-<programlisting>
-ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
-</programlisting>
- Note that this doesn't affect any existing rows in the table, it
- just changes the default for future <command>INSERT</> commands.
- </para>
+ <indexterm>
+ <primary>inheritance</primary>
+ </indexterm>
- <para>
- To remove any default value, use
-<programlisting>
-ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
-</programlisting>
- This is effectively the same as setting the default to null.
- As a consequence, it is not an error
- to drop a default where one hadn't been defined, because the
- default is implicitly the null value.
- </para>
- </sect2>
+ <indexterm>
+ <primary>table</primary>
+ <secondary>inheritance</secondary>
+ </indexterm>
- <sect2>
- <title>Changing a Column's Data Type</title>
+ <para>
+ <productname>PostgreSQL</productname> implements table inheritance
+ which can be a useful tool for database designers. (SQL:1999 and
+ later define a type inheritance feature, which differs in many
+ respects from the features described here.)
+ </para>
- <indexterm>
- <primary>column data type</primary>
- <secondary>changing</secondary>
- </indexterm>
+ <para>
+ Let's start with an example: suppose we are trying to build a data
+ model for cities. Each state has many cities, but only one
+ capital. We want to be able to quickly retrieve the capital city
+ for any particular state. This can be done by creating two tables,
+ one for state capitals and one for cities that are not
+ capitals. However, what happens when we want to ask for data about
+ a city, regardless of whether it is a capital or not? The
+ inheritance feature can help to resolve this problem. We define the
+ <structname>capitals</structname> table so that it inherits from
+ <structname>cities</structname>:
- <para>
- To convert a column to a different data type, use a command like this:
<programlisting>
-ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
-</programlisting>
- This will succeed only if each existing entry in the column can be
- converted to the new type by an implicit cast. If a more complex
- conversion is needed, you can add a <literal>USING</> clause that
- specifies how to compute the new values from the old.
- </para>
+CREATE TABLE cities (
+ name text,
+ population float,
+ altitude int -- in feet
+);
- <para>
- <productname>PostgreSQL</> will attempt to convert the column's
- default value (if any) to the new type, as well as any constraints
- that involve the column. But these conversions may fail, or may
- produce surprising results. It's often best to drop any constraints
- on the column before altering its type, and then add back suitably
- modified constraints afterwards.
- </para>
- </sect2>
+CREATE TABLE capitals (
+ state char(2)
+) INHERITS (cities);
+</programlisting>
- <sect2>
- <title>Renaming a Column</title>
+ In this case, the <structname>capitals</> table <firstterm>inherits</>
+ all the columns of its parent table, <structname>cities</>. State
+ capitals also have an extra column, <structfield>state</>, that shows
+ their state.
+ </para>
- <indexterm>
- <primary>column</primary>
- <secondary>renaming</secondary>
- </indexterm>
+ <para>
+ In <productname>PostgreSQL</productname>, a table can inherit from
+ zero or more other tables, and a query can reference either all
+ rows of a table or all rows of a table plus all of its descendant tables.
+ The latter behavior is the default.
+ For example, the following query finds the names of all cities,
+ including state capitals, that are located at an altitude over
+ 500ft:
- <para>
- To rename a column:
<programlisting>
-ALTER TABLE products RENAME COLUMN product_no TO product_number;
+SELECT name, altitude
+ FROM cities
+ WHERE altitude > 500;
</programlisting>
- </para>
- </sect2>
- <sect2>
- <title>Renaming a Table</title>
-
- <indexterm>
- <primary>table</primary>
- <secondary>renaming</secondary>
- </indexterm>
+ Given the sample data from the <productname>PostgreSQL</productname>
+ tutorial (see <xref linkend="tutorial-sql-intro">), this returns:
- <para>
- To rename a table:
<programlisting>
-ALTER TABLE products RENAME TO items;
+ name | altitude
+-----------+----------
+ Las Vegas | 2174
+ Mariposa | 1953
+ Madison | 845
</programlisting>
- </para>
- </sect2>
- </sect1>
-
- <sect1 id="ddl-priv">
- <title>Privileges</title>
+ </para>
- <indexterm zone="ddl-priv">
- <primary>privilege</primary>
- </indexterm>
+ <para>
+ On the other hand, the following query finds all the cities that
+ are not state capitals and are situated at an altitude over 500ft:
- <indexterm>
- <primary>permission</primary>
- <see>privilege</see>
- </indexterm>
+<programlisting>
+SELECT name, altitude
+ FROM ONLY cities
+ WHERE altitude > 500;
- <para>
- When you create a database object, you become its owner. By
- default, only the owner of an object can do anything with the
- object. In order to allow other users to use it,
- <firstterm>privileges</firstterm> must be granted. (However,
- users that have the superuser attribute can always
- access any object.)
+ name | altitude
+-----------+----------
+ Las Vegas | 2174
+ Mariposa | 1953
+</programlisting>
</para>
<para>
- There are several different privileges: <literal>SELECT</>,
- <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
- <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
- <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>, and
- <literal>USAGE</>. The privileges applicable to a particular
- object vary depending on the object's type (table, function, etc).
- For complete information on the different types of privileges
- supported by <productname>PostgreSQL</productname>, refer to the
- <xref linkend="sql-grant" endterm="sql-grant-title"> reference
- page. The following sections and chapters will also show you how
- those privileges are used.
+ Here the <literal>ONLY</literal> keyword indicates that the query
+ should apply only to <structname>cities</structname>, and not any tables
+ below <structname>cities</structname> in the inheritance hierarchy. Many
+ of the commands that we have already discussed —
+ <command>SELECT</command>, <command>UPDATE</command> and
+ <command>DELETE</command> — support the
+ <literal>ONLY</literal> keyword.
</para>
<para>
- The right to modify or destroy an object is always the privilege of
- the owner only.
- </para>
+ In some cases you may wish to know which table a particular row
+ originated from. There is a system column called
+ <structfield>tableoid</structfield> in each table which can tell you the
+ originating table:
- <note>
- <para>
- To change the owner of a table, index, sequence, or view, use the
- <xref linkend="sql-altertable" endterm="sql-altertable-title">
- command. There are corresponding <literal>ALTER</> commands for
- other object types.
- </para>
- </note>
+<programlisting>
+SELECT c.tableoid, c.name, c.altitude
+FROM cities c
+WHERE c.altitude > 500;
+</programlisting>
+
+ which returns:
- <para>
- To assign privileges, the <command>GRANT</command> command is
- used. For example, if <literal>joe</literal> is an existing user, and
- <literal>accounts</literal> is an existing table, the privilege to
- update the table can be granted with
<programlisting>
-GRANT UPDATE ON accounts TO joe;
+ tableoid | name | altitude
+----------+-----------+----------
+ 139793 | Las Vegas | 2174
+ 139793 | Mariposa | 1953
+ 139798 | Madison | 845
</programlisting>
- To grant a privilege to a group, use this syntax:
+
+ (If you try to reproduce this example, you will probably get
+ different numeric OIDs.) By doing a join with
+ <structname>pg_class</> you can see the actual table names:
+
<programlisting>
-GRANT SELECT ON accounts TO GROUP staff;
+SELECT p.relname, c.name, c.altitude
+FROM cities c, pg_class p
+WHERE c.altitude > 500 and c.tableoid = p.oid;
+</programlisting>
+
+ which returns:
+
+<programlisting>
+ relname | name | altitude
+----------+-----------+----------
+ cities | Las Vegas | 2174
+ cities | Mariposa | 1953
+ capitals | Madison | 845
</programlisting>
- The special <quote>user</quote> name <literal>PUBLIC</literal> can
- be used to grant a privilege to every user on the system. Writing
- <literal>ALL</literal> in place of a specific privilege grants all
- privileges that are relevant for the object type.
</para>
<para>
- To revoke a privilege, use the fittingly named
- <command>REVOKE</command> command:
+ Inheritance does not automatically propagate data from
+ <command>INSERT</command> or <command>COPY</command> commands to
+ other tables in the inheritance hierarchy. In our example, the
+ following <command>INSERT</command> statement will fail:
<programlisting>
-REVOKE ALL ON accounts FROM PUBLIC;
+INSERT INTO cities (name, population, altitude, state)
+VALUES ('New York', NULL, NULL, 'NY');
</programlisting>
- The special privileges of the object owner (i.e., the right to do
- <command>DROP</>, <command>GRANT</>, <command>REVOKE</>, etc.)
- are always implicit in being the owner,
- and cannot be granted or revoked. But the object owner can choose
- to revoke his own ordinary privileges, for example to make a
- table read-only for himself as well as others.
+ We might hope that the data would somehow be routed to the
+ <structname>capitals</structname> table, but this does not happen:
+ <command>INSERT</command> always inserts into exactly the table
+ specified. In some cases it is possible to redirect the insertion
+ using a rule (see <xref linkend="rules">). However that does not
+ help for the above case because the <structname>cities</> table
+ does not contain the column <structfield>state</>, and so the
+ command will be rejected before the rule can be applied.
</para>
<para>
- Ordinarily, only the object's owner (or a superuser) can grant or
- revoke privileges on an object. However, it is possible to grant a
- privilege <quote>with grant option</>, which gives the recipient
- the right to grant it in turn to others. If the grant option is
- subsequently revoked then all who received the privilege from that
- recipient (directly or through a chain of grants) will lose the
- privilege. For details see the <xref linkend="sql-grant"
- endterm="sql-grant-title"> and <xref linkend="sql-revoke"
- endterm="sql-revoke-title"> reference pages.
+ Check constraints can be defined on tables within an inheritance
+ hierarchy. All check constraints on a parent table are
+ automatically inherited by all of its children. Other types of
+ constraints are not inherited, however.
</para>
- </sect1>
- <sect1 id="ddl-schemas">
- <title>Schemas</title>
+ <para>
+ A table can inherit from more than one parent table, in which case it has
+ the union of the columns defined by the parent tables. Any columns
+ declared in the child table's definition are added to these. If the
+ same column name appears in multiple parent tables, or in both a parent
+ table and the child's definition, then these columns are <quote>merged</>
+ so that there is only one such column in the child table. To be merged,
+ columns must have the same data types, else an error is raised. The
+ merged column will have copies of all the check constraints coming from
+ any one of the column definitions it came from.
+ </para>
- <indexterm zone="ddl-schemas">
- <primary>schema</primary>
- </indexterm>
+ <para>
+ Table inheritance can currently only be defined using the <xref
+ linkend="sql-createtable" endterm="sql-createtable-title">
+ statement. The related statement <command>CREATE TABLE AS</command> does
+ not allow inheritance to be specified. There
+ is no way to add an inheritance link to make an existing table into
+ a child table. Similarly, there is no way to remove an inheritance
+ link from a child table once it has been defined, other than by dropping
+ the table completely. A parent table cannot be dropped
+ while any of its children remain. If you wish to remove a table and
+ all of its descendants, one easy way is to drop the parent table with
+ the <literal>CASCADE</literal> option.
+ </para>
<para>
- A <productname>PostgreSQL</productname> database cluster
- contains one or more named databases. Users and groups of users are
- shared across the entire cluster, but no other data is shared across
- databases. Any given client connection to the server can access
- only the data in a single database, the one specified in the connection
- request.
+ <xref linkend="sql-altertable" endterm="sql-altertable-title"> will
+ propagate any changes in column data definitions and check
+ constraints down the inheritance hierarchy. Again, dropping
+ columns or constraints on parent tables is only possible when using
+ the <literal>CASCADE</literal> option. <command>ALTER
+ TABLE</command> follows the same rules for duplicate column merging
+ and rejection that apply during <command>CREATE TABLE</command>.
</para>
- <note>
- <para>
- Users of a cluster do not necessarily have the privilege to access every
- database in the cluster. Sharing of user names means that there
- cannot be different users named, say, <literal>joe</> in two databases
- in the same cluster; but the system can be configured to allow
- <literal>joe</> access to only some of the databases.
- </para>
- </note>
+ <sect2 id="ddl-inherit-caveats">
+ <title>Caveats</title>
<para>
- A database contains one or more named <firstterm>schemas</>, which
- in turn contain tables. Schemas also contain other kinds of named
- objects, including data types, functions, and operators. The same
- object name can be used in different schemas without conflict; for
- example, both <literal>schema1</> and <literal>myschema</> may
- contain tables named <literal>mytable</>. Unlike databases,
- schemas are not rigidly separated: a user may access objects in any
- of the schemas in the database he is connected to, if he has
- privileges to do so.
+ Table access permissions are not automatically inherited. Therefore,
+ a user attempting to access a parent table must either have permissions
+ to do the operation on all its child tables as well, or must use the
+ <literal>ONLY</literal> notation. When adding a new child table to
+ an existing inheritance hierarchy, be careful to grant all the needed
+ permissions on it.
</para>
-
+
<para>
- There are several reasons why one might want to use schemas:
+ A serious limitation of the inheritance feature is that indexes (including
+ unique constraints) and foreign key constraints only apply to single
+ tables, not to their inheritance children. This is true on both the
+ referencing and referenced sides of a foreign key constraint. Thus,
+ in the terms of the above example:
<itemizedlist>
<listitem>
<para>
- To allow many users to use one database without interfering with
- each other.
+ If we declared <structname>cities</>.<structfield>name</> to be
+ <literal>UNIQUE</> or a <literal>PRIMARY KEY</>, this would not stop the
+ <structname>capitals</> table from having rows with names duplicating
+ rows in <structname>cities</>. And those duplicate rows would by
+ default show up in queries from <structname>cities</>. In fact, by
+ default <structname>capitals</> would have no unique constraint at all,
+ and so could contain multiple rows with the same name.
+ You could add a unique constraint to <structname>capitals</>, but this
+ would not prevent duplication compared to <structname>cities</>.
</para>
</listitem>
<listitem>
<para>
- To organize database objects into logical groups to make them
- more manageable.
+ Similarly, if we were to specify that
+ <structname>cities</>.<structfield>name</> <literal>REFERENCES</> some
+ other table, this constraint would not automatically propagate to
+ <structname>capitals</>. In this case you could work around it by
+ manually adding the same <literal>REFERENCES</> constraint to
+ <structname>capitals</>.
</para>
</listitem>
<listitem>
<para>
- Third-party applications can be put into separate schemas so
- they cannot collide with the names of other objects.
+ Specifying that another table's column <literal>REFERENCES
+ cities(name)</> would allow the other table to contain city names, but
+ not capital names. There is no good workaround for this case.
</para>
</listitem>
</itemizedlist>
- Schemas are analogous to directories at the operating system level,
- except that schemas cannot be nested.
+ These deficiencies will probably be fixed in some future release,
+ but in the meantime considerable care is needed in deciding whether
+ inheritance is useful for your problem.
</para>
- <sect2 id="ddl-schemas-create">
- <title>Creating a Schema</title>
-
- <indexterm zone="ddl-schemas-create">
- <primary>schema</primary>
- <secondary>creating</secondary>
- </indexterm>
-
+ <note>
+ <title>Deprecated</title>
<para>
- To create a schema, use the command <command>CREATE
- SCHEMA</command>. Give the schema a name of your choice. For
- example:
+ In previous versions of <productname>PostgreSQL</productname>, the
+ default behavior was not to include child tables in queries. This was
+ found to be error prone and is also in violation of the SQL
+ standard. Under the old syntax, to include the child tables you append
+ <literal>*</literal> to the table name. For example:
<programlisting>
-CREATE SCHEMA myschema;
+SELECT * from cities*;
</programlisting>
+ You can still explicitly specify scanning child tables by
+ appending <literal>*</literal>, as well as explicitly specify not
+ scanning child tables by writing <literal>ONLY</literal>. But
+ beginning in version 7.1, the default behavior for an undecorated
+ table name is to scan its child tables too, whereas before the
+ default was not to do so. To get the old default behavior,
+ disable the <xref linkend="guc-sql-inheritance"> configuration
+ option.
</para>
+ </note>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="ddl-partitioning">
+ <title>Partitioning</title>
<indexterm>
- <primary>qualified name</primary>
+ <primary>partitioning</primary>
</indexterm>
<indexterm>
- <primary>name</primary>
- <secondary>qualified</secondary>
+ <primary>table</primary>
+ <secondary>partitioning</secondary>
</indexterm>
<para>
- To create or access objects in a schema, write a
- <firstterm>qualified name</> consisting of the schema name and
- table name separated by a dot:
-<synopsis>
-<replaceable>schema</><literal>.</><replaceable>table</>
-</synopsis>
- This works anywhere a table name is expected, including the table
- modification commands and the data access commands discussed in
- the following chapters.
- (For brevity we will speak of tables only, but the same ideas apply
- to other kinds of named objects, such as types and functions.)
+ <productname>PostgreSQL</productname> supports basic table
+ partitioning. This section describes why and how you can implement
+ partitioning as part of your database design.
</para>
+ <sect2 id="ddl-partitioning-overview">
+ <title>Overview</title>
+
<para>
- Actually, the even more general syntax
-<synopsis>
-<replaceable>database</><literal>.</><replaceable>schema</><literal>.</><replaceable>table</>
-</synopsis>
- can be used too, but at present this is just for <foreignphrase>pro
- forma</> compliance with the SQL standard. If you write a database name,
- it must be the same as the database you are connected to.
+ Partitioning refers to splitting what is logically one large table
+ into smaller physical pieces.
+ Partitioning can provide several benefits:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Query performance can be improved dramatically for certain kinds
+ of queries.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Update performance can be improved too, since each piece of the table
+ has indexes smaller than an index on the entire data set would be.
+ When an index no longer fits easily
+ in memory, both read and write operations on the index take
+ progressively more disk accesses.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Bulk deletes may be accomplished by simply removing one of the
+ partitions, if that requirement is planned into the partitioning design.
+ <command>DROP TABLE</> is far faster than a bulk <command>DELETE</>,
+ to say nothing of the ensuing <command>VACUUM</> overhead.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Seldom-used data can be migrated to cheaper and slower storage media.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ The benefits will normally be worthwhile only when a table would
+ otherwise be very large. The exact point at which a table will
+ benefit from partitioning depends on the application, although a
+ rule of thumb is that the size of the table should exceed the physical
+ memory of the database server.
</para>
<para>
- So to create a table in the new schema, use
-<programlisting>
-CREATE TABLE myschema.mytable (
- ...
-);
-</programlisting>
+ Currently, <productname>PostgreSQL</productname> supports partitioning
+ via table inheritance. Each partition must be created as a child
+ table of a single parent table. The parent table itself is normally
+ empty; it exists just to represent the entire data set. You should be
+ familiar with inheritance (see <xref linkend="ddl-inherit">) before
+ attempting to implement partitioning.
</para>
- <indexterm>
- <primary>schema</primary>
- <secondary>removing</secondary>
- </indexterm>
+ <para>
+ The following forms of partitioning can be implemented in
+ <productname>PostgreSQL</productname>:
+
+ <variablelist>
+ <varlistentry>
+ <term>Range Partitioning</term>
+
+ <listitem>
+ <para>
+ The table is partitioned into <quote>ranges</quote> defined
+ by a key column or set of columns, with no 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.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>List Partitioning</term>
+
+ <listitem>
+ <para>
+ The table is partitioned by explicitly listing which key values
+ appear in each partition.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ Hash partitioning is not currently supported.
+ </para>
+ </sect2>
+
+ <sect2 id="ddl-partitioning-implementation">
+ <title>Implementing Partitioning</title>
+
+ <para>
+ To set up a partitioned table, do the following:
+ <orderedlist spacing=compact>
+ <listitem>
+ <para>
+ Create the <quote>master</quote> table, from which all of the
+ partitions will inherit.
+ </para>
+ <para>
+ This table will contain no data. Do not define any check
+ constraints on this table, unless you intend them to
+ be applied equally to all partitions. There is no point
+ in defining any indexes or unique constraints on it, either.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Create several <quote>child</quote> tables that each inherit from
+ the master table. Normally, these tables will not add any columns
+ to the set inherited from the master.
+ </para>
+
+ <para>
+ We will refer to the child tables as partitions, though they
+ are in every way normal <productname>PostgreSQL</> tables.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Add table constraints to the partition tables to define the
+ allowed key values in each partition.
+ </para>
- <para>
- To drop a schema if it's empty (all objects in it have been
- dropped), use
+ <para>
+ Typical examples would be:
<programlisting>
-DROP SCHEMA myschema;
+CHECK ( x = 1 )
+CHECK ( county IN ( 'Oxfordshire', 'Buckinghamshire', 'Warwickshire' ))
+CHECK ( outletID >= 100 AND outletID < 200 )
</programlisting>
- To drop a schema including all contained objects, use
+ Ensure that the constraints guarantee that there is no overlap
+ between the key values permitted in different partitions. A common
+ mistake is to set up range constraints like this:
<programlisting>
-DROP SCHEMA myschema CASCADE;
+CHECK ( outletID BETWEEN 100 AND 200 )
+CHECK ( outletID BETWEEN 200 AND 300 )
</programlisting>
- See <xref linkend="ddl-depend"> for a description of the general
- mechanism behind this.
- </para>
+ This is wrong since it is not clear which partition the key value
+ 200 belongs in.
+ </para>
- <para>
- Often you will want to create a schema owned by someone else
- (since this is one of the ways to restrict the activities of your
- users to well-defined namespaces). The syntax for that is:
-<programlisting>
-CREATE SCHEMA <replaceable>schemaname</replaceable> AUTHORIZATION <replaceable>username</replaceable>;
-</programlisting>
- You can even omit the schema name, in which case the schema name
- will be the same as the user name. See <xref
- linkend="ddl-schemas-patterns"> for how this can be useful.
- </para>
+ <para>
+ Note that there is no difference in
+ syntax between range and list partitioning; those terms are
+ descriptive only.
+ </para>
+ </listitem>
- <para>
- Schema names beginning with <literal>pg_</> are reserved for
- system purposes and may not be created by users.
- </para>
- </sect2>
+ <listitem>
+ <para>
+ For each partition, create an index on the key column(s),
+ as well as any other indexes you might want. (The key index is
+ not strictly necessary, but in most scenarios it is helpful.
+ If you intend the key values to be unique then you should
+ always create a unique or primary-key constraint for each
+ partition.)
+ </para>
+ </listitem>
- <sect2 id="ddl-schemas-public">
- <title>The Public Schema</title>
+ <listitem>
+ <para>
+ Optionally, define a rule or trigger to redirect modifications
+ of the master table to the appropriate partition.
+ </para>
+ </listitem>
- <indexterm zone="ddl-schemas-public">
- <primary>schema</primary>
- <secondary>public</secondary>
- </indexterm>
+ <listitem>
+ <para>
+ Ensure that the <xref linkend="guc-constraint-exclusion">
+ configuration
+ parameter is enabled in <filename>postgresql.conf</>. Without
+ this, queries will not be optimized as desired.
+ </para>
+ </listitem>
+
+ </orderedlist>
+ </para>
+
+ <para>
+ For example, suppose we are constructing a database for a large
+ ice cream company. The company measures peak temperatures every
+ day as well as ice cream sales in each region. Conceptually,
+ we want a table like this:
- <para>
- In the previous sections we created tables without specifying any
- schema names. By default, such tables (and other objects) are
- automatically put into a schema named <quote>public</quote>. Every new
- database contains such a schema. Thus, the following are equivalent:
-<programlisting>
-CREATE TABLE products ( ... );
-</programlisting>
- and
<programlisting>
-CREATE TABLE public.products ( ... );
+CREATE TABLE measurement (
+ city_id int not null,
+ logdate date not null,
+ peaktemp int,
+ unitsales int
+);
</programlisting>
- </para>
- </sect2>
- <sect2 id="ddl-schemas-path">
- <title>The Schema Search Path</title>
+ We know that most queries will access just the last week's, month's or
+ quarter's data, since the main use of this table will be to prepare
+ online reports for management.
+ To reduce the amount of old data that needs to be stored, we
+ decide to only keep the most recent 3 years worth of data. At the
+ beginning of each month we will remove the oldest month's data.
+ </para>
- <indexterm>
- <primary>search path</primary>
- </indexterm>
+ <para>
+ In this situation we can use partitioning to help us meet all of our
+ different requirements for the measurements table. Following the
+ steps outlined above, partitioning can be set up as follows:
+ </para>
- <indexterm>
- <primary>unqualified name</primary>
- </indexterm>
+ <para>
+ <orderedlist spacing=compact>
+ <listitem>
+ <para>
+ The master table is the <structname>measurement</> table, declared
+ exactly as above.
+ </para>
+ </listitem>
- <indexterm>
- <primary>name</primary>
- <secondary>unqualified</secondary>
- </indexterm>
+ <listitem>
+ <para>
+ Next we create one partition for each active month:
- <para>
- Qualified names are tedious to write, and it's often best not to
- wire a particular schema name into applications anyway. Therefore
- tables are often referred to by <firstterm>unqualified names</>,
- which consist of just the table name. The system determines which table
- is meant by following a <firstterm>search path</>, which is a list
- of schemas to look in. The first matching table in the search path
- is taken to be the one wanted. If there is no match in the search
- path, an error is reported, even if matching table names exist
- in other schemas in the database.
- </para>
+<programlisting>
+CREATE TABLE measurement_yy04mm02 ( ) INHERITS (measurement);
+CREATE TABLE measurement_yy04mm03 ( ) INHERITS (measurement);
+...
+CREATE TABLE measurement_yy05mm11 ( ) INHERITS (measurement);
+CREATE TABLE measurement_yy05mm12 ( ) INHERITS (measurement);
+CREATE TABLE measurement_yy06mm01 ( ) INHERITS (measurement);
+</programlisting>
- <indexterm>
- <primary>schema</primary>
- <secondary>current</secondary>
- </indexterm>
+ Each of the partitions are complete tables in their own right,
+ but they inherit their definition from the
+ <structname>measurement</> table.
+ </para>
- <para>
- The first schema named in the search path is called the current schema.
- Aside from being the first schema searched, it is also the schema in
- which new tables will be created if the <command>CREATE TABLE</>
- command does not specify a schema name.
- </para>
+ <para>
+ This solves one of our problems: deleting old data. Each
+ month, all we will need to do is perform a <command>DROP
+ TABLE</command> on the oldest child table and create a new
+ child table for the new month's data.
+ </para>
+ </listitem>
- <indexterm>
- <primary>search_path</primary>
- </indexterm>
+ <listitem>
+ <para>
+ We must add non-overlapping table constraints, so that our
+ table creation script becomes:
- <para>
- To show the current search path, use the following command:
-<programlisting>
-SHOW search_path;
+ <programlisting>
+CREATE TABLE measurement_yy04mm02 (
+ CHECK ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
+) INHERITS (measurement);
+CREATE TABLE measurement_yy04mm03 (
+ CHECK ( logdate >= DATE '2004-03-01' AND logdate < DATE '2004-04-01' )
+) INHERITS (measurement);
+...
+CREATE TABLE measurement_yy05mm11 (
+ CHECK ( logdate >= DATE '2005-11-01' AND logdate < DATE '2005-12-01' )
+) INHERITS (measurement);
+CREATE TABLE measurement_yy05mm12 (
+ CHECK ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
+) INHERITS (measurement);
+CREATE TABLE measurement_yy06mm01 (
+ CHECK ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
+) INHERITS (measurement);
</programlisting>
- In the default setup this returns:
-<screen>
- search_path
---------------
- $user,public
-</screen>
- The first element specifies that a schema with the same name as
- the current user is to be searched. If no such schema exists,
- the entry is ignored. The second element refers to the
- public schema that we have seen already.
- </para>
+ </para>
+ </listitem>
- <para>
- The first schema in the search path that exists is the default
- location for creating new objects. That is the reason that by
- default objects are created in the public schema. When objects
- are referenced in any other context without schema qualification
- (table modification, data modification, or query commands) the
- search path is traversed until a matching object is found.
- Therefore, in the default configuration, any unqualified access
- again can only refer to the public schema.
- </para>
+ <listitem>
+ <para>
+ We probably need indexes on the key columns too:
- <para>
- To put our new schema in the path, we use
-<programlisting>
-SET search_path TO myschema,public;
+ <programlisting>
+CREATE INDEX measurement_yy04mm02_logdate ON measurement_yy04mm02 (logdate);
+CREATE INDEX measurement_yy04mm03_logdate ON measurement_yy04mm03 (logdate);
+...
+CREATE INDEX measurement_yy05mm11_logdate ON measurement_yy05mm11 (logdate);
+CREATE INDEX measurement_yy05mm12_logdate ON measurement_yy05mm12 (logdate);
+CREATE INDEX measurement_yy06mm01_logdate ON measurement_yy06mm01 (logdate);
</programlisting>
- (We omit the <literal>$user</literal> here because we have no
- immediate need for it.) And then we can access the table without
- schema qualification:
+
+ We choose not to add further indexes at this time.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If data will be added only to the latest partition, we can
+ set up a very simple rule to insert data. We must
+ redefine this each month so that it always points to the
+ current partition.
+
<programlisting>
-DROP TABLE mytable;
+CREATE OR REPLACE RULE measurement_current_partition AS
+ON INSERT TO measurement
+DO INSTEAD
+ INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
+ NEW.logdate,
+ NEW.peaktemp,
+ NEW.unitsales );
</programlisting>
- Also, since <literal>myschema</literal> is the first element in
- the path, new objects would by default be created in it.
- </para>
- <para>
- We could also have written
+ We might want to insert data and have the server automatically
+ locate the partition into which the row should be added. We
+ could do this with a more complex set of rules as shown below.
+
<programlisting>
-SET search_path TO myschema;
+CREATE RULE measurement_insert_yy04mm02 AS
+ON INSERT TO measurement WHERE
+ ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
+DO INSTEAD
+ INSERT INTO measurement_yy04mm02 VALUES ( NEW.city_id,
+ NEW.logdate,
+ NEW.peaktemp,
+ NEW.unitsales );
+...
+CREATE RULE measurement_insert_yy05mm12 AS
+ON INSERT TO measurement WHERE
+ ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
+DO INSTEAD
+ INSERT INTO measurement_yy05mm12 VALUES ( NEW.city_id,
+ NEW.logdate,
+ NEW.peaktemp,
+ NEW.unitsales );
+CREATE RULE measurement_insert_yy06mm01 AS
+ON INSERT TO measurement WHERE
+ ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
+DO INSTEAD
+ INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
+ NEW.logdate,
+ NEW.peaktemp,
+ NEW.unitsales );
</programlisting>
- Then we no longer have access to the public schema without
- explicit qualification. There is nothing special about the public
- schema except that it exists by default. It can be dropped, too.
- </para>
+
+ Note that the <literal>WHERE</literal> clause in each rule
+ exactly matches the the <literal>CHECK</literal>
+ constraint for its partition.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+
+ <para>
+ As we can see, a complex partitioning scheme could require a
+ substantial amount of DDL. In the above example we would be
+ creating a new partition each month, so it may be wise to write a
+ script that generates the required DDL automatically.
+ </para>
<para>
- See also <xref linkend="functions-info"> for other ways to manipulate
- the schema search path.
+ The following caveats apply:
+ <itemizedlist>
+ <listitem>
+ <para>
+ There is currently no way to verify that all of the
+ <literal>CHECK</literal> constraints are mutually
+ exclusive. Care is required by the database designer.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ There is currently no simple way to specify that rows must not be
+ inserted into the master table. A <literal>CHECK (false)</literal>
+ constraint on the master table would be inherited by all child
+ tables, so that cannot be used for this purpose. One possibility is
+ to set up an <literal>ON INSERT</> trigger on the master table that
+ always raises an error. (Alternatively, such a trigger could be
+ used to redirect the data into the proper child table, instead of
+ using a set of rules as suggested above.)
+ </para>
+ </listitem>
+ </itemizedlist>
</para>
<para>
- The search path works in the same way for data type names, function names,
- and operator names as it does for table names. Data type and function
- names can be qualified in exactly the same way as table names. If you
- need to write a qualified operator name in an expression, there is a
- special provision: you must write
-<synopsis>
-<literal>OPERATOR(</><replaceable>schema</><literal>.</><replaceable>operator</><literal>)</>
-</synopsis>
- This is needed to avoid syntactic ambiguity. An example is
+ Partitioning can also be arranged using a <literal>UNION ALL</literal>
+ view:
+
<programlisting>
-SELECT 3 OPERATOR(pg_catalog.+) 4;
+CREATE VIEW measurement AS
+ SELECT * FROM measurement_yy04mm02
+UNION ALL SELECT * FROM measurement_yy04mm03
+...
+UNION ALL SELECT * FROM measurement_yy05mm11
+UNION ALL SELECT * FROM measurement_yy05mm12
+UNION ALL SELECT * FROM measurement_yy06mm01;
</programlisting>
- In practice one usually relies on the search path for operators,
- so as not to have to write anything so ugly as that.
+
+ However, constraint exclusion is currently not supported for
+ partitioned tables defined in this manner. Also, the need to
+ recreate the view adds an extra step to adding and dropping
+ individual partitions of the dataset.
</para>
- </sect2>
+ </sect2>
- <sect2 id="ddl-schemas-priv">
- <title>Schemas and Privileges</title>
+ <sect2 id="ddl-partitioning-constraint-exclusion">
+ <title>Partitioning and Constraint Exclusion</title>
- <indexterm zone="ddl-schemas-priv">
- <primary>privilege</primary>
- <secondary sortas="schemas">for schemas</secondary>
+ <indexterm>
+ <primary>constraint exclusion</primary>
</indexterm>
<para>
- By default, users cannot access any objects in schemas they do not
- own. To allow that, the owner of the schema needs to grant the
- <literal>USAGE</literal> privilege on the schema. To allow users
- to make use of the objects in the schema, additional privileges
- may need to be granted, as appropriate for the object.
- </para>
+ <firstterm>Constraint exclusion</> is a query optimization technique
+ that improves performance for partitioned tables defined in the
+ fashion described above. As an example:
- <para>
- A user can also be allowed to create objects in someone else's
- schema. To allow that, the <literal>CREATE</literal> privilege on
- the schema needs to be granted. Note that by default, everyone
- has <literal>CREATE</literal> and <literal>USAGE</literal> privileges on
- the schema
- <literal>public</literal>. This allows all users that are able to
- connect to a given database to create objects in its
- <literal>public</literal> schema. If you do
- not want to allow that, you can revoke that privilege:
<programlisting>
-REVOKE CREATE ON SCHEMA public FROM PUBLIC;
+SET constraint_exclusion = on;
+SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
</programlisting>
- (The first <quote>public</quote> is the schema, the second
- <quote>public</quote> means <quote>every user</quote>. In the
- first sense it is an identifier, in the second sense it is a
- key word, hence the different capitalization; recall the
- guidelines from <xref linkend="sql-syntax-identifiers">.)
+
+ Without constraint exclusion, the above query would scan each of
+ the partitions of the <structname>measurement</> table. With constraint
+ exclusion enabled, the planner will examine the constraints of each
+ partition and try to prove that the partition need not
+ be scanned because it could not contain any rows meeting the query's
+ <literal>WHERE</> clause. When the planner can prove this, it
+ excludes the partition from the query plan.
</para>
- </sect2>
- <sect2 id="ddl-schemas-catalog">
- <title>The System Catalog Schema</title>
+ <para>
+ You can use the <command>EXPLAIN</> command to show the difference
+ between a plan with <varname>constraint_exclusion</> on and a plan
+ with it off. A typical default plan for this type of table setup is:
- <indexterm zone="ddl-schemas-catalog">
- <primary>system catalog</primary>
- <secondary>schema</secondary>
- </indexterm>
+<programlisting>
+SET constraint_exclusion = off;
+EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
- <para>
- In addition to <literal>public</> and user-created schemas, each
- database contains a <literal>pg_catalog</> schema, which contains
- the system tables and all the built-in data types, functions, and
- operators. <literal>pg_catalog</> is always effectively part of
- the search path. If it is not named explicitly in the path then
- it is implicitly searched <emphasis>before</> searching the path's
- schemas. This ensures that built-in names will always be
- findable. However, you may explicitly place
- <literal>pg_catalog</> at the end of your search path if you
- prefer to have user-defined names override built-in names.
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Aggregate (cost=158.66..158.68 rows=1 width=0)
+ -> Append (cost=0.00..151.88 rows=2715 width=0)
+ -> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+ -> Seq Scan on measurement_yy04mm02 measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+ -> Seq Scan on measurement_yy04mm03 measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+...
+ -> Seq Scan on measurement_yy05mm12 measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+ -> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+</programlisting>
+
+ Some or all of the partitions might use index scans instead of
+ full-table sequential scans, but the point here is that there
+ is no need to scan the older partitions at all to answer this query.
+ When we enable constraint exclusion, we get a significantly
+ reduced plan that will deliver the same answer:
+
+<programlisting>
+SET constraint_exclusion = on;
+EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Aggregate (cost=63.47..63.48 rows=1 width=0)
+ -> Append (cost=0.00..60.75 rows=1086 width=0)
+ -> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+ -> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0)
+ Filter: (logdate >= '2006-01-01'::date)
+</programlisting>
</para>
<para>
- In <productname>PostgreSQL</productname> versions before 7.3,
- table names beginning with <literal>pg_</> were reserved. This is
- no longer true: you may create such a table name if you wish, in
- any non-system schema. However, it's best to continue to avoid
- such names, to ensure that you won't suffer a conflict if some
- future version defines a system table named the same as your
- table. (With the default search path, an unqualified reference to
- your table name would be resolved as the system table instead.)
- System tables will continue to follow the convention of having
- names beginning with <literal>pg_</>, so that they will not
- conflict with unqualified user-table names so long as users avoid
- the <literal>pg_</> prefix.
+ Note that constraint exclusion is driven only by <literal>CHECK</>
+ constraints, not by the presence of indexes. Therefore it isn't
+ necessary to define indexes on the key columns. Whether an index
+ needs to be created for a given partition depends on whether you
+ expect that queries that scan the partition will generally scan
+ a large part of the partition or just a small part. An index will
+ be helpful in the latter case but not the former.
</para>
- </sect2>
-
- <sect2 id="ddl-schemas-patterns">
- <title>Usage Patterns</title>
<para>
- Schemas can be used to organize your data in many ways. There are
- a few usage patterns that are recommended and are easily supported by
- the default configuration:
- <itemizedlist>
- <listitem>
- <para>
- If you do not create any schemas then all users access the
- public schema implicitly. This simulates the situation where
- schemas are not available at all. This setup is mainly
- recommended when there is only a single user or a few cooperating
- users in a database. This setup also allows smooth transition
- from the non-schema-aware world.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can create a schema for each user with the same name as
- that user. Recall that the default search path starts with
- <literal>$user</literal>, which resolves to the user name.
- Therefore, if each user has a separate schema, they access their
- own schemas by default.
- </para>
+ The following caveats apply:
- <para>
- If you use this setup then you might also want to revoke access
- to the public schema (or drop it altogether), so users are
- truly constrained to their own schemas.
- </para>
- </listitem>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Constraint exclusion only works when the query's <literal>WHERE</>
+ clause contains constants. A parameterized query will not be
+ optimized, since the planner cannot know what partitions the
+ parameter value might select at runtime. For the same reason,
+ <quote>stable</> functions such as <function>CURRENT_DATE</function>
+ must be avoided. Joining the partition key to a column of another
+ table will not be optimized, either.
+ </para>
+ </listitem>
- <listitem>
- <para>
- To install shared applications (tables to be used by everyone,
- additional functions provided by third parties, etc.), put them
- into separate schemas. Remember to grant appropriate
- privileges to allow the other users to access them. Users can
- then refer to these additional objects by qualifying the names
- with a schema name, or they can put the additional schemas into
- their search path, as they choose.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </sect2>
+ <listitem>
+ <para>
+ Avoid cross-datatype comparisons in the <literal>CHECK</>
+ constraints, as the planner will currently fail to prove such
+ conditions false. For example, the following constraint
+ will work if <varname>x</varname> is an <type>integer</type>
+ column, but not if <varname>x</varname> is a
+ <type>bigint</type>:
+<programlisting>
+CHECK ( x = 1 )
+</programlisting>
+ For a <type>bigint</type> column we must use a constraint like:
+<programlisting>
+CHECK ( x = 1::bigint )
+</programlisting>
+ The problem is not limited to the <type>bigint</type> data type
+ — it can occur whenever the default data type of the
+ constant does not match the data type of the column to which it
+ is being compared. Cross-datatype comparisons in the supplied
+ queries are usually OK, just not in the <literal>CHECK</> conditions.
+ </para>
+ </listitem>
- <sect2 id="ddl-schemas-portability">
- <title>Portability</title>
+ <listitem>
+ <para>
+ <command>UPDATE</command> and <command>DELETE</command> commands
+ against the master table do not currently perform constraint exclusion.
+ </para>
+ </listitem>
- <para>
- In the SQL standard, the notion of objects in the same schema
- being owned by different users does not exist. Moreover, some
- implementations do not allow you to create schemas that have a
- different name than their owner. In fact, the concepts of schema
- and user are nearly equivalent in a database system that
- implements only the basic schema support specified in the
- standard. Therefore, many users consider qualified names to
- really consist of
- <literal><replaceable>username</>.<replaceable>tablename</></literal>.
- This is how <productname>PostgreSQL</productname> will effectively
- behave if you create a per-user schema for every user.
- </para>
+ <listitem>
+ <para>
+ All constraints on all partitions of the master table are considered for
+ constraint exclusion, so large numbers of partitions are likely to
+ increase query planning time considerably.
+ </para>
+ </listitem>
- <para>
- Also, there is no concept of a <literal>public</> schema in the
- SQL standard. For maximum conformance to the standard, you should
- not use (perhaps even remove) the <literal>public</> schema.
- </para>
+ <listitem>
+ <para>
+ Don't forget that you still need to run <command>ANALYZE</command>
+ on each partition individually. A command like
+<programlisting>
+ANALYZE measurement;
+</programlisting>
+ will only process the master table.
+ </para>
+ </listitem>
- <para>
- Of course, some SQL database systems might not implement schemas
- at all, or provide namespace support by allowing (possibly
- limited) cross-database access. If you need to work with those
- systems, then maximum portability would be achieved by not using
- schemas at all.
+ </itemizedlist>
</para>
</sect2>
</sect1>
</screen>
and all the dependent objects will be removed. In this case, it
doesn't remove the orders table, it only removes the foreign key
- constraint. (If you want to check what <literal>DROP ... CASCADE</> will do,
+ constraint. (If you want to check what <command>DROP ... CASCADE</> will do,
run <command>DROP</> without <literal>CASCADE</> and read the <literal>NOTICE</> messages.)
</para>