On Mon, 2005-10-31 at 02:46 +0000, Simon Riggs wrote: > I've been working on some docs for Constraining Exclusion & Partitioning > for some time now. Deadlines seem to be looming, or may even have > passed, so it seems sensible to submit what I have now.
> Many thanks to Josh Berkus for providing the numbered section on > implementation process, which was the starting point I'd been looking > for to describe everything else. I believe this is now complete and ready for application. - passes sgml make against cvstip - spellchecked - all code executed correctly against RC1 Comments please? Apart from the obvious, so why did it take you so long. Apologies to the translators. Best Regards, Simon Riggs
Index: ddl.sgml =================================================================== RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ddl.sgml,v retrieving revision 1.45 diff -c -c -r1.45 ddl.sgml *** ddl.sgml 23 Oct 2005 19:29:49 -0000 1.45 --- ddl.sgml 31 Oct 2005 22:36:26 -0000 *************** *** 398,403 **** --- 398,410 ---- ensure that a column does not contain null values, the not-null 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> </sect2> <sect2> *************** *** 1040,1052 **** <sect1 id="ddl-inherit"> <title>Inheritance</title> ! <remark>This section needs to be rethought. Some of the ! information should go into the following chapters.</remark> <para> ! Let's create two tables. The capitals table contains ! state capitals which are also cities. Naturally, the ! capitals table should inherit from cities. <programlisting> CREATE TABLE cities ( --- 1047,1081 ---- <sect1 id="ddl-inherit"> <title>Inheritance</title> ! <indexterm> ! <primary>not-null constraint</primary> ! </indexterm> ! ! <indexterm> ! <primary>constraint</primary> ! <secondary>NOT NULL</secondary> ! </indexterm> ! ! <para> ! <productname>PostgreSQL</productname> was the first DBMS to introduce ! inheritance, one of its many object-relational features. ! <productname>PostgreSQL</productname> implements table ! inheritance which can be a useful tool for database designers. ! The SQL:2003 standard optionally defines type inheritance which differs ! in many respects from the features described here. ! </para> <para> ! Let's start with an example: ! We're trying to build a data model for cities, but we have a problem. ! Each state has many cities, but only one capital. We want to be able ! to quickly retrieve the capital city for any particular state. We ! can solve this problem by creating two tables. The capitals table contains ! state capitals, then we have another table for cities that aren't capitals. ! What happens when we want to ask for data about a city, regardless of ! whether it is a capital or not? We can use the inheritance feature to ! help resolve this problem for us. We define the capitals table so that ! it inherits from cities. <programlisting> CREATE TABLE cities ( *************** *** 1062,1077 **** In this case, a row of capitals <firstterm>inherits</firstterm> all attributes (name, population, and altitude) from its parent, cities. State ! capitals have an extra attribute, state, that shows their state. 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. - - <note> - <para> - The inheritance hierarchy is actually a directed acyclic graph. - </para> - </note> </para> <para> --- 1091,1102 ---- In this case, a row of capitals <firstterm>inherits</firstterm> all attributes (name, population, and altitude) from its parent, cities. State ! capitals have an extra attribute, state, that shows their state. ! </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. </para> <para> *************** *** 1133,1163 **** </para> </note> ! <note> ! <title>Deprecated</title> ! <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:2003 ! standard. Under the old syntax, to get the sub-tables you append ! <literal>*</literal> to the table name. ! For example ! <programlisting> ! 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 <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, set the configuration option ! <literal>SQL_Inheritance</literal> to off, e.g., ! <programlisting> ! SET SQL_Inheritance TO OFF; ! </programlisting> ! or add a line in your <filename>postgresql.conf</filename> file. ! </para> ! </note> <para> In some cases you may wish to know which table a particular row --- 1158,1180 ---- </para> </note> ! <para> ! Inheritance does not automatically propogate data from INSERT or COPY ! commands to other tables in the inheritance hierarchy. Inheritance ! does not influence these commands. ! In our example, the following INSERT statement will fail. ! <programlisting> ! INSERT INTO cities ! (name, population, altitude, state) ! VALUES ('New York', NULL, NULL, 'NY'); ! </programlisting> ! We might hope that the data would be somehow routed to the capitals 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 INSERT statement ! because the 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 *************** *** 1204,1220 **** </para> <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 (plus any columns ! declared specifically for the child table). </para> <para> ! 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> --- 1221,1287 ---- </para> <para> ! As shown above, a child table may locally define columns as ! well as inheriting them from their parents. ! However, polymorphism of table datatypes is not supported: a locally defined ! column cannot override the datatype of an inherited column of the same name. ! </para> ! ! <para> ! 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 has the union of the columns defined by the parent ! tables (plus any columns declared locally for the child table). ! Inherited columns with duplicate names and datatypes will be merged so ! that only a single column is stored. An inheritance definition that ! results in a column with more than one datatype would not succeed. ! The full inheritance hierarchy is actually a directed acyclic graph of ! arbitrary complexity. You should note that complex inheritance hierarchies ! will cause a corresponding increase in parsing time for your queries. ! Direct access to the specific table your query requires will always ! provide the best performance. </para> <para> ! Table inheritance can currently only be defined using the ! <xref linkend="SQL-CREATETABLE"> statement. ! The related statement CREATE TABLE ... AS SELECT does ! not allow the specification of an inheritance link. The ALTER TABLE statement ! does not currently support the INHERITS() clause. 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 defined, other than using DROP TABLE on the child table. ! 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 CASCADE option of the <xref linkend="SQL-DROPTABLE"> statement. ! </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. Note that is currently possible to ! inherit mutually exclusive check constraints, but that definition quickly ! shows itself since all attempted row inserts will be rejected. ! </para> ! ! <para> ! <xref linkend="SQL-ALTERTABLE"> 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 CASCADE option. ALTER TABLE follows the same rules for ! duplicate column merging and rejection that apply during CREATE TABLE. ! </para> ! ! <para> ! Both parent and child tables can have primary and foreign keys ! defined for them, 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: <itemizedlist> <listitem> *************** *** 1236,1244 **** 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> --- 1303,1313 ---- 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. </para> </listitem> *************** *** 1251,1260 **** --- 1320,1922 ---- </listitem> </itemizedlist> + Some statements are not optimised in the same way for inherited tables + as they are for normal tables. Examples include: + + <itemizedlist> + <listitem> + <para>MIN/MAX aggregates with no GROUP BY + <programlisting> + SELECT MIN(foo) FROM bar; + </programlisting> + </para> + </listitem> + + <listitem> + <para>Retrieving rows from an ordered result set using an index + <programlisting> + SELECT foo FROM bar ORDER BY foo LIMIT 5; + </programlisting> + </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. + </para> + + <note> + <title>Deprecated</title> + <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:2003 + standard. Under the old syntax, to get the sub-tables you append + <literal>*</literal> to the table name. + For example + <programlisting> + 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 <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, set the configuration option + <literal>SQL_Inheritance</literal> to off, e.g., + <programlisting> + SET SQL_Inheritance TO OFF; + </programlisting> + or add a line in your <filename>postgresql.conf</filename> file. + </para> + </note> + + </sect1> + + <sect1 id="ce-partitioning"> + <title>Constraint Exclusion and Partitioning</title> + + <indexterm> + <primary>partitioning</primary> + </indexterm> + + <indexterm> + <primary>constraint exclusion</primary> + </indexterm> + + <para> + <productname>PostgreSQL</productname> provides features required + to support basic table partitioning. This section describes why and how + you can implement this as part of your database design. + </para> + + <sect2 id="ce-partitioning-overview"> + <title>Partitioning Overview</title> + + <para> + Currently, partitioning is implemented in conjunction with table + inheritance only, though using fully SQL:2003 compliant syntax. + Table inheritance gives us the ability to split up a table into partitions + and the Constraint Exclusion feature provides the ability to selectively + bring partitions back together in response to particular SELECT statements. + You should be familiar with Inheritance (see <xref linkend="ddl-inherit">) + before attempting to implement partitioning. + </para> + + <para> + Partitioning can provide a number of benefits. + <itemizedlist> + <listitem> + <para> + Query performance can be improved dramatically for certain kinds + of query without the need for maintaining 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> + + <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> + + <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 data table would + otherwise be very large. That is for you to judge, though would not + usually be lower than the size of physical RAM on the database server. + Partitioning can be of use in any type of application. Examples range from + data warehousing applications with large historical data stores through + to line-of-business applications such as order-entry, CRM or ERP systems. + </para> + + <para> + In &version; the following partitioning types are supported: + <itemizedlist> + <listitem> + <para> + "Range Partitioning" where the table is partitioned along a "range" + defined by a single column or set of columns, with no overlap between + partitions. Examples might be a date range (e.g. LogDate) or a range of + identifiers for particular business objects (e.g. OrderId). + </para> + </listitem> + + <listitem> + <para> + "List Partitioning" where the table is partitioned by explicitly listing + which values relate to each partition. + </para> + </listitem> + + <listitem> + <para> + Mixed range and list partitioning. No restrictions are placed on the + number or complexity of the partitioning constraints. + </para> + </listitem> + + <listitem> + <para> + Hash partitioning is not currently supported. + </para> + </listitem> + </itemizedlist> + </para> + + <para> + In the next section <xref linkend="ce-partitioning-implementation"> we + discuss how to create the DDL required for partitioning. We then move on + to a discussion of the Constraint Exclusion feature which allows + query performance to be improved, in + <xref linkend="constraint-exclusion-queries"> + </para> + + </sect2> + + + <sect2 id="ce-partitioning-implementation"> + <title>Implementing Partitioning</title> + + <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> + + <para> + <orderedlist spacing=compact> + <listitem> + <para> + Create the "master" table, from which all of the partitions of that + will master will inherit. + </para> + <para> + This table will contain no data. Do not define any + constraints or keys on this table at this time, unless you intend them + to be applied equally to all partitions. + </para> + </listitem> + + <listitem> + <para> + Create several "child" tables using table inheritance to create + identical copies of the master table. + </para> + <para> + We will refer to the child tables as partitions, though they are in + every way just normal PostgreSQL data tables. It is advisable to + devise a progressive naming scheme for the partitions. + </para> + </listitem> + + <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: + <programlisting> + CHECK ( x = 1 ) + CHECK ( county IN ('Oxfordshire','Buckinghamshire','Warwickshire')) + CHECK ( outletID BETWEEN 1 AND 99 ) + </programlisting> + + These can be linked together with boolean operators AND and OR to + form complex constraints. Note that there is no difference in syntax + between Range and List Partitioning mechanisms; 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 on the partitions, bearing in mind + that it is always more efficient to add them after data has been + loaded into the partition. + </para> + </listitem> + + <listitem> + <para> + (optional) Define a RULE or trigger which tells the database which + partition in which to put new data. + </para> + </listitem> + + </orderedlist> + </para> + + + <para> + Now lets look at the process again using a worked example of 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 ft) + ); + + CREATE TABLE measurement ( + city_id int not null, + logdate date not null, + peaktemp int, + unitsales int + ); + </programlisting> + + As time goes on, sales data is entered. Storing data costs money, + yet older data has less value as ice cream fashions change, so we decide + to keep only 3 years data on a rolling 36 months. 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. + </para> + + <para> + (Step 1) The measurement table is our master table. + </para> + + <para> + (Step 2) Next we create 36 month-size partitions, using the PostgreSQL + inheritance feature like this: + + <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 tables 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 older data. Each month, all + we need to do is perform a DROP TABLE on the oldest table and create + a new table to insert into. + </para> + + <para> + (Step 3) 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> + + Note that we use constants in the CHECK constraints rather than a + calculation involving INTERVALS. + </para> + + <para> + (Step 4) We choose not to add further indices at this time. + </para> + + <para> + (Step 5) 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 WHERE clauses in each RULE exactly match those used + for the CHECK constraints on each partition. + </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 would be advisable to create a script/program that + generates the SQL DDL required automatically rather than manually + maintaining all of the required code. + </para> + + <para> + The following caveats apply: + <itemizedlist> + <listitem> + <para> + There is currently no way to specify that all of the CHECK 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. Any CHECK constraint on the master + table will be inherited by all child tables, so could not be used for + that purpose. + </para> + </listitem> + + <listitem> + <para> + For some datatypes you must explicitly coerce the constant values + into the datatype of the column. The following constraint will + work if x is an INTEGER datatype, but not if x is BIGINT datatype. + <programlisting> + CHECK ( x = 1) + </programlisting> + For BIGINT we must use a constraint like: + <programlisting> + CHECK ( x = 1::bigint) + </programlisting> + The issue is not restricted to BIGINT datatypes but can occur whenever + the default datatype of the constant does not match the datatype of + the column to which it is being compared. + </para> + </listitem> + <listitem> + <para> + There is currently no way to specify that rows may not be inserted + into the master table. If you define a CHECK constraint on the master + table, then this constraint will be inherited by all child tables. All + queries will then return no rows. + </para> + </listitem> + + <listitem> + <para> + Partitioning can also be arranged using a UNION ALL view, such as the + following 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, in this release this means of specifying a + partitioned table does not support Constraint Exclusion and is not + recommended. + </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 the Constraint Exclusion (CE) feature. 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> + You can use the EXPLAIN command to show the difference + between a plan with 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 CE, we get a significantly reduced plan, yet one that + returns exactly the same answer (provably). + + <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 ANALYZE on each partition + individually. A simple command like this + <programlisting> + ANALYZE measurement; + </programlisting> + + does not ANALYZE each of the partitions, only the master table. + </para> + + <para> + No indexes are required to make CE function. The partitions should be + defined with appropriate CHECK constraints + and these are able to be compared against clauses on the query. + </para> + + <para> + The following caveats apply to this release: + <itemizedlist> + <listitem> + <para> + CE only works when the query directly matches a constant. A + constant bound to a parameterised 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 CURRENT_DATE may not be used, since + these are constant only for during the execution of a single query. + Joins conditions will not allow CE to work either. + </para> + </listitem> + + <listitem> + <para> + UPDATEs and DELETEs against the partitioning master table do + not perform constraint exclusion. One of the purposes of + partitioning is to avoid bulk DELETE statements so you are advised + to rethink your design if you attempting this. + </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 parse time considerably. + </para> + </listitem> + + </itemizedlist> + </para> + + </sect2> + </sect1> <sect1 id="ddl-alter">
---------------------------(end of broadcast)--------------------------- TIP 3: Have you checked our extensive FAQ? http://www.postgresql.org/docs/faq