4

我根据http://www.postgresql.org/docs/8.1/interactive/ddl-partitioning.html上的文档设置了一组分区表

CREATE TABLE t (year, a);
CREATE TABLE t_1980 ( CHECK (year = 1980) ) INHERITS (t);
CREATE TABLE t_1981 ( CHECK (year = 1981) ) INHERITS (t);
CREATE RULE t_ins_1980 AS ON INSERT TO t WHERE (year = 1980)
    DO INSTEAD INSERT INTO t_1980 VALUES (NEW.year, NEW.a);
CREATE RULE t_ins_1981 AS ON INSERT TO t WHERE (year = 1981)
    DO INSTEAD INSERT INTO t_1981 VALUES (NEW.year, NEW.a);

据我了解,如果我 INSERT INTO t (year, a) VALUES (1980, 5),它将转到 t_1980,如果我 INSERT INTO t (year, a) VALUES (1981, 3),它将转到 t_1981 . 但是,我的理解似乎是不正确的。首先,我无法从文档中理解以下内容

“目前没有简单的方法来指定行不能插入到主表中。主表上的 CHECK (false) 约束将被所有子表继承,因此不能用于此目的。一种可能性是在总是引发错误的主表上设置 ON INSERT 触发器。(或者,可以使用这样的触发器将数据重定向到正确的子表,而不是使用上面建议的一组规则。)“

以上是否意味着尽管设置了 CHECK 约束和 RULE,我还必须在主表上创建 TRIGGER,以便 INSERT 进入正确的表?如果是这种情况,那么数据库支持分区的意义何在?我可以自己设置单独的表格吗?我在主表中插入了一堆值,这些行仍然在主表中,而不是在继承表中。

第二个问题。检索行时,我是从主表中选择,还是必须根据需要从各个表中选择?以下如何工作?

SELECT year, a FROM t WHERE year IN (1980, 1981);

更新:好像我已经找到了我自己问题的答案

“请注意,COPY 命令会忽略规则。如果您使用 COPY 插入数据,则必须将数据复制到正确的子表中,而不是复制到父表中。COPY 会触发触发器,因此如果您创建分区,则可以正常使用它使用触发器方法的表。”

我确实使用 COPY FROM 来加载数据,因此忽略了规则。将尝试使用触发器。

4

3 回答 3

4

一定要试试触发器。

如果你认为你想实现一个规则,不要(想到的唯一例外是可更新视图)。有关更多解释,请参阅depesz 的这篇精彩文章。

实际上,Postgres 仅支持在事物的读取方面进行分区。您将自己设置插入分区的方法 - 在大多数情况下触发。根据需要和应用程序,有时教您的应用程序直接插入分区会更快。

从分区表中选择时,只要正确设置了 CHECK 约束(它们在您的示例中)并且正确设置了 constraint_exclusion 参数,您确实可以在主表上选择 ... WHERE ... 。

对于 8.4:

SET constraint_exclusion = partition;

对于 < 8.4:

SET constraint_exclusion = on;

说了这么多,其实我真的很喜欢 Postgres 的做法,而且我自己也经常使用它。

于 2010-06-19T14:24:24.717 回答
1

触发器肯定比规则好。今天我玩了物化视图表的分区并遇到了触发器解决方案的问题。为什么 ?我正在使用 RETURNING 并且当前解决方案返回 NULL :) 但是这里的解决方案对我有用 - 如果我错了,请纠正我。1. 我有 3 个表,其中插入了一些数据,有一个视图(我们称之为 viewfoo),其中包含需要物化的数据。2. 插入最后一个表有触发器,该触发器通过 INSERT INTO matviewtable SELECT * FROM viewfoo WHERE recno=NEW.recno 插入物化视图表;效果很好,我正在使用 RETURNING recno; (recno 是 SERIAL 类型 - 序列)。

物化视图(表)需要分区,因为它很大,根据我的测试,在这种情况下,SELECT 至少要快 10 倍。分区问题: * 当前触发解决方案 RETURN NULL - 所以我不能使用 RETURNING recno。(当前触发器解决方案 = depesz 页面上解释的触发器)。

解决方案:我已将我的第三个表的触发器更改为不插入物化视图表(该表是分区表的父表),但创建了直接从第三个表插入分区表并触发 RETURN NEW 的新触发器。物化视图表会自动更新,并且 RETURNING recno 工作正常。如果这对任何人都有帮助,我会很高兴。

于 2012-02-03T18:32:21.903 回答
1

以上是否意味着尽管设置了 CHECK 约束和 RULE,我还必须在主表上创建 TRIGGER,以便 INSERT 进入正确的表?

是的。阅读第 5 点(第 5.9.2 节)

如果是这种情况,那么数据库支持分区的意义何在?我可以自己设置单独的表格吗?

基本上:子表中的 INSERTS 必须显式完成(创建 TRIGGERS,或通过在查询中指定正确的子表)。但是分区对于 SELECTS 是透明的,并且(鉴于此模式的存储和索引优势)这就是重点。(此外,因为分区表是继承的,所以模式是从父表继承的,因此强制执行一致性)。

于 2010-06-19T17:52:14.657 回答