postgresql - 如何将 Postgres 外键模拟到分区表中

标签 postgresql foreign-keys postgresql-9.3 database-partitioning

我有一个分区表(称为 A),它的串行主键被另一个表(称为 B)引用。我知道我不能实际上创建一个从一个到另一个的外键(因为我不知道数据实际上是从哪个分区存储的),所以相反,我试图模仿使用检查约束的外键行为。类似于以下内容:

CREATE TABLE A (
    MyKey SERIAL PRIMARY KEY
);

CREATE TABLE B (
    AKey INT, -- Should have: REFERENCES A (MyKey),
              -- but can't due to Postgres limitations
);

CREATE TABLE APart1 (
    Field1 INT,
    PRIMARY KEY (MyKey)
) INHERITS (A);

CREATE TABLE APart2 (
    Field2 INT,
    PRIMARY KEY (MyKey)
) INHERITS (A);

CREATE FUNCTION ValidateKeyInA(aKey INT) RETURNS BOOL AS $$
    BEGIN
        PERFORM * FROM A WHERE MyKey = aKey;
        IF FOUND THEN
            RETURN TRUE;
        END IF;
        RETURN FALSE;
    END;
$$ LANGUAGE PLPGSQL;

ALTER TABLE B ADD CHECK (ValidateKeyInA(AKey));

WITH aKey AS (INSERT INTO APart1 (Field1) VALUES (1) RETURNING MyKey)
INSERT INTO B (AKey) SELECT * FROM aKey;

WITH aKey AS (INSERT INTO APart2 (Field2) VALUES (2) RETURNING MyKey)
INSERT INTO B (AKey) SELECT * FROM aKey;

这工作得很好,直到我转储并恢复数据库。那时,Postgres 不知道表 B 依赖于表 A(及其分区)中的数据,而 B 恰好在表 A 之前被转储。我试图在我所在的行中添加“DEFERRABLE”关键字添加约束,但 Postgres 不支持可延迟检查约束。

我建议的方法是将我的检查约束转换为约束触发器,我可以推迟,然后在事务中导入我的数据库转储。对此有更直接的方法吗?例如,有什么方法可以告诉 Postgres 在转储表 A 及其所有分区之前不要转储表 B(例如,将 B 的依赖项添加到 A 的分区)?我应该改用其他一些模式吗?谢谢。

最佳答案

pg_dump 按字母顺序自动对表格进行排序(请参阅我上面的评论)。然而,如果你想改变表被转储和恢复的顺序但不能根据所需的顺序重命名你的表,你可以使用带有 pg_restore 的 --use-list 选项。参见 http://www.postgresql.org/docs/9.3/static/app-pgrestore.html

pg_restore 允许控制顺序,如何使用选项 --use-list 恢复数据库元素。

您必须首先使用选项 -Fc 以自定义格式转储数据库,否则您无法使用 pg_restore 恢复转储:

pg_dump -Fc your_database -f database.dump

然后生成一个文件,其中列出了转储中的所有元素:

pg_restore --list database.dump > backup.txt

文件 backup.txt 将用作 pg_restore 选项 --use-list 的输入,但首先您可以编辑该文件并使用复制/粘贴更改行的顺序。您可以独立更改表创建和数据插入。请注意您的列表保持一致。您还可以完全删除行,以便从恢复中排除元素。

最后使用选项 --use-list 恢复你的转储:

pg_restore -d your_database --use-list backup.txt database.dump

我用你的例子测试了这个过程并改变了表 A 和 B 的顺序。如果首先恢复表 A,转储将被恢复而没有错误。否则,如果先恢复 B,则恢复会按预期失败并出现错误:

pg_restore: [archiver (db)] COPY failed for table "b": ERROR: new row for relation "b" violates check constraint "b_akey_check" DETAIL: Failing row contains (1). CONTEXT: COPY b, line 1: "1" WARNING: errors ignored on restore: 1

关于postgresql - 如何将 Postgres 外键模拟到分区表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28822484/

相关文章:

PostgreSQL 9.3 : REPLACE string

sql - 更改用户的默认架构

postgresql - 如何在Postgres数据库中添加模式描述?

mysql - postgresql vs mysql 易于扩展,以及对高度相关(大量外键)数据库的实用性

postgresql - 模式的转储结构和数据

postgresql - 如何在 PostgreSQL 的函数中返回查询结果行?

sql - 将 2 列合并为一列 SQL

sql - 复杂的 Join Query,Join 3 tables with multiple group bys

python - Django 外键选择

c# - Entity Framework 0..1 到 0 的关系