【问题标题】:How to ensure validity of foreign keys in Postgres如何确保 Postgres 中外键的有效性
【发布时间】:2019-01-10 00:41:05
【问题描述】:

使用 Postgres 10.6

问题:

  • 我的表中的某些数据违反了外键约束(不确定如何)。约束是ON DELETE CASCADE ON UPDATE CASCADE
  • 在数据库的 pg_dump 上,这些外键被删除(由于处于无效状态?)
  • pg_restore 写入一个不再有外键的空白数据库
  • 新数据库已将其所有主键更新为第二个数据库中未使用的有效键。由于现在缺少约束,包含无效数据的表没有更新其外键。
  • 新数据库的pg_dump完成,然后数据库被删除
  • 在将 pg_restore 导入具有外键约束的第二个数据库时,数据以无效状态导入,并损坏新数据库。

我想要做的是:每隔几个小时(或一天一次,取决于查询需要多长时间)验证所有具有外键的表中的所有数据是否有效。

我已阅读有关ALTER TABLE ... VALIDATE CONSTRAINT ... 的信息,但这不能解决我的问题,因为数据当前未标记为NOT VALID。我知道可以做这样的陈述:

DELETE FROM a WHERE a.b_id NOT IN ( SELECT b.id )

但是,我有 144 个带有外键的表,所以这会相当乏味。我也可能不想立即删除数据,但记录问题并通知用户将会发生的更正。

当然,我想知道最初的损坏是如何发生的,并防止这种情况发生;但是目前我只是想阻止它传播。

示例表:

CREATE TABLE dependencies (
    ...
    from_task int references tasks(id) ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, 
    to_task int references tasks(id) ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, 
    ...
);

依赖关系最终会得到 to_taskfrom_task 的值,这在 tasks 表中不存在(见图)

注意:

  • 试过EXPLAINANALYZE没什么奇怪的
  • pg_tablespace,只有两条记录。 pg_default 和 pg_global
  • relforcerowsecurity、relispartition 在两个表上都是“假”
  • pg_dump 的参数(来自 c++ 调用)arguments << "--file=" + fileName << "--username=" + connection.userName() << databaseName << "--format=c"

【问题讨论】:

  • “我的表中的一些数据违反了外键约束(不确定如何)”不知何故我非常怀疑..为我们提供创建表语句和违反的数据
  • 除非先填表,否则稍后会用NOT VALID选项添加外键,对吧?
  • 外键从一开始就存在。我已编辑帖子以包含其中一张表的相关部分。
  • 以下查询为您的表 SELECT relname, relrowsecurity FROM pg_class where relname='tasks' 返回什么?
  • relrowsecurity 为假。

标签: postgresql foreign-keys data-corruption


【解决方案1】:

这要么是索引(或表)损坏问题,要么是创建的约束无效以将有效性检查推迟到以后。

pg_dump 永远不会默默地“删除”约束 — 可能在恢复您没有注意到的转储时出现错误。

正确的解决方法是清理违反约束的数据并重新创建它。

如果是数据损坏问题,请检查您的硬件。

不需要定期检查数据损坏,PostgreSQL没有自己损坏数据的习惯。

最好的测试是定期使用pg_dump,看看恢复转储是否会导致任何错误。

【讨论】:

  • 在某些时候,我不知道如何,数据库获取了无效的数据。在转储/恢复过程中(如您所说,可能是恢复),由于数据无效,约束被“删除”。通过更改 pg_restore 命令上的一些选项,我们能够检测到故障并中止事务,从而至少防止进一步的损坏。它仍然没有解释初始数据库是如何损坏的;也不提供修复原始错误的方法。我想要一种不断检查的方法的原因是或多或少地了解用户正在做什么导致错误。错误记录
  • 数据损坏不是由用户引起的,而是由硬件或软件错误引起的。需要注意的是崩溃(特别是如果存储不可靠)和日志中的错误消息。
  • 在三台不同的计算机上,一个用户始终如一地发生这种情况。所以,我不愿意认为硬件是一个问题。下次她出现问题时,我会查看她的日志。
  • 我是否理解正确:您有一个 PostgreSQL 数据库,可以正常转储和恢复,然后某个用户连接并且某些数据库工作,然后数据库损坏?如果它发生在多台机器上,数据库如何从一台机器移动到另一台机器?通过物理备份还是使用pg_dump?如果您的数据库已损坏,您应该在解决问题后将其转储并恢复到不同的集群。数据库损坏可能是“不可见的”并且可以传播,因此可能是您没有通过修复几个数据来解决问题。
  • pg_dump 然后 pg_restore 是我们移动它的方式。用户最终删除了他们的整个数据库,并备份了表。一两个星期后,它似乎又回来了。她她不会重新导入已损坏的旧项目。
猜你喜欢
  • 2018-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多