【问题标题】:How can a relational database with foreign key constraints ingest data that may be in the wrong order?具有外键约束的关系数据库如何摄取可能顺序错误的数据?
【发布时间】:2020-01-14 05:35:32
【问题描述】:

数据库正在从流中提取数据,满足外键约束所需的所有行可能会延迟或永远不会到达。

这可以通过使用另一个数据存储来完成,一个没有外键约束的数据存储,然后当所有需要的数据都可用时,读入具有 fk 约束的数据库。但是,这会增加复杂性,我想避免它。

我们正在研究创建“占位符”行以将外键指向的解决方案。当真实数据进来时,占位符被替换为真实值。同样,这增加了复杂性,但这是我们迄今为止找到的最佳解决方案。

人们通常如何解决这个问题?

编辑:一些可能有助于解释问题的示例数据:

假设我们有这些表:

CREATE TABLE order (
  id INTEGER NOT NULL,
  order_number,
  PRIMARY KEY (id),
  UNIQUE (order_number)
);

CREATE TABLE line_item (
  id INTEGER NOT NULL,
  order_number INTEGER REFERENCES order(order_number),
  PRIMARY KEY (id)
);

如果我先下单,没问题!但假设我尝试:

INSERT INTO line_item (order_number) values (123) 在插入订单 123 之前。这当然会使 fk 约束失败。但这可能是我获取数据的顺序,因为它是从从多个来源收集这些数据的流中读取的。

另外,为了解决@philpxy 的问题,我在这方面并没有真正找到太多。提到的一件事是deferred constraints。这是一种在事务结束时等待执行 fk 约束的机制。但是,我认为在我的情况下不可能这样做,因为这些插入语句将在收到数据时随机运行。

【问题讨论】:

  • 您能否添加一些有助于解释问题的示例数据?
  • 您的研究表明了什么? How to Askhelp center
  • @TimBiegeleisen 我在问题中添加了一个示例。
  • 如果你不是在事务结束时寻找一致性,那么什么时候(什么时候)数据应该处于一致状态?

标签: postgresql foreign-keys referential-integrity data-ingestion


【解决方案1】:

您遇到了业务工作流程问题,因为单个订单的订单项在订单本身进入之前就进入了。一种可能并不理想的解决方法是创建一个插入前触发器,该触发器检查每个进入的插入到line_item 表中,该订单是否已存在于 order 表中。如果没有,那么它会先插入订单记录,然后再尝试在line_item 上插入。

CREATE OR REPLACE FUNCTION "public"."fn_insert_order" () RETURNS trigger AS $$
BEGIN
    INSERT INTO "order" (order_number)
    SELECT NEW.order_number
    WHERE NOT EXISTS (SELECT 1 FROM "order" WHERE order_number = NEW.order_number);
    RETURN NEW;
END
$$
LANGUAGE 'plpgsql'

# trigger 
CREATE TRIGGER "trigger_insert_order"
BEFORE INSERT ON line_item FOR EACH ROW
EXECUTE PROCEDURE fn_insert_order()

注意:我假设order 表的id 列实际上是自动递增的,在这种情况下,Postgres 在插入时会自动为其分配一个值。这很可能是您想要的,因为有两个需要手动分配的 id 列没有多大意义。

【讨论】:

    【解决方案2】:

    您可以在line_item 上使用BEFORE INSERT 触发器来完成此操作。 在该触发器中,您查询 order 是否存在匹配项,如果不存在,则插入一个虚拟行。

    这将使INSERT 能够成功,但会牺牲一些性能。

    要将行插入order,请使用

    INSERT INTO order ...
    ON CONFLICT ON (order_number) DO UPDATE SET
       id = EXCLUDED.id;
    

    更新主键有问题,可能会导致冲突。解决这个问题的一种方法是,如果您对人为生成的订单使用负数 ids(假设真正的 ids 是正数)。如果您对该主键有任何引用,则必须使用 ON UPDATE CASCADE 定义约束。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-03
      • 1970-01-01
      • 2016-10-14
      • 2021-11-03
      • 2011-04-30
      • 1970-01-01
      相关资源
      最近更新 更多