【问题标题】:How do I INSERT and SELECT data with partitioned tables?如何使用分区表插入和选择数据?
【发布时间】:2011-03-05 18:21:24
【问题描述】:

我根据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 来加载数据,因此忽略了规则。将尝试使用 TRIGGER。

【问题讨论】:

    标签: postgresql rules partitioning


    【解决方案1】:

    触发器肯定比规则好。 今天我玩了物化视图表的分区并遇到了触发器解决方案的问题。 为什么 ? 我正在使用 RETURNING 并且当前解决方案返回 NULL :) 但这里的解决方案对我有用 - 如果我错了,请纠正我。 1. 我有 3 个表,其中插入了一些数据,有一个视图(我们称之为 viewfoo),其中包含 需要物化的数据。 2.insert into last table 有插入物化视图表的触发器 通过 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 工作正常。 如果这对任何人都有帮助,我会很高兴。

    【讨论】:

      【解决方案2】:

      一定要试试触发器。

      如果您认为自己想要实施规则,那就不要(想到的唯一例外是可更新视图)。有关详细说明,请参阅此great article by depesz

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

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

      对于 8.4:

      SET constraint_exclusion = partition;
      

      对于

      SET constraint_exclusion = on;
      

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

      【讨论】:

        【解决方案3】:

        以上是否意味着尽管 设置 CHECK 约束和 规则,我也必须创建 主表上的触发器,以便 INSERT 会转到正确的表吗?

        是的。阅读point 5 (section 5.9.2)

        如果是这样的话,会是什么 db支持的点 分区?我可以设置 自己分开表?

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

        【讨论】:

          猜你喜欢
          • 2020-02-10
          • 2019-03-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-10
          • 1970-01-01
          • 2013-01-04
          相关资源
          最近更新 更多