如何在Postgres中建模多表“继承”?

时间:2017-04-04 02:15:39

标签: sql database postgresql schema

我正在尝试在Postgres数据库中建模一些需要“继承”的不同用例,并意识到有多种方法可以做到这一点,我不确定哪种方法最好。

我正在考虑的两个具体用例是:

  • “会员资格” - 单个“用户”可以是不同类型对象的成员:“团队”,“集合”或“项目”。在这种情况下,成员类型的上限是这三种关系类型。 (现在。)

  • “事件” - 可以创建与我的数据模型中任何其他对象相关的“事件” - 例如。 “teams.create”,“users.update”,“webhooks.create”,“items.publish”等。在这种情况下,关系的“类型”并没有真正限制,因为每当我添加新的数据模型时,我很有可能想要为它创建事件。

以下是我可以看到实现这些需求的一些方法......

(对这些代码片段使用“Memberships”用例,但同样适用于“Events”用例。)

1。 XOR列

CREATE TABLE memberships (
  id TEXT,
  user_id TEXT,
  team_id TEXT,
  collection_id TEXT,
  item_id TEXT,
  PRIMARY KEY (id),
  FOREIGN KEY (user_id) REFERENCES users (id),
  FOREIGN KEY (team_id) REFERENCES teams (id),
  FOREIGN KEY (collection_id) REFERENCES collections (id),
  FOREIGN KEY (item_id) REFERENCES items (id),
  CHECK (
    (team_id IS NOT NULL)::integer + 
    (collection_id IS NOT NULL)::integer +
    (item_id IS NOT NULL)::integer = 1
  )
);

优点:

  • 数据库为您处理外来关系。
  • JOIN s不那么冗长。

缺点:

  • 每行都有额外的NULL列值。
  • CHECK约束有点奇怪吗?
  • 新“类型”需要添加*_id列并更改CHECK

2。一对列

CREATE TABLE memberships (
  id TEXT,
  user_id TEXT,
  target_type TEXT,
  target_id TEXT,
  PRIMARY KEY (id),
  FOREIGN KEY (user_id) REFERENCES users (id),
  CHECK (target_type IN ('team', 'collection', 'items'))
);

优点:

  • 添加新“类型”不需要添加列。
  • 每行没有额外的NULL列值。
  • 您不需要约束来确保每行只存在一个目标。

缺点:

  • 您必须保证应用程序层中的数据一致性。
  • 编写JOIN个查询有点冗长。
  • 添加新“类型”时,您必须更改CHECK约束。

3。许多表

CREATE TABLE team_memberships (
  id TEXT,
  user_id TEXT,
  team_id TEXT,
  PRIMARY KEY (id),
  FOREIGN KEY (user_id) REFERENCES users (id),
  FOREIGN KEY (team_id) REFERENCES teams (id)
);

CREATE TABLE collection_memberships (
  id TEXT,
  user_id TEXT,
  collection_id TEXT,
  PRIMARY KEY (id),
  FOREIGN KEY (user_id) REFERENCES users (id),
  FOREIGN KEY (collection_id) REFERENCES collections (id)
);

CREATE TABLE item_memberships (
  id TEXT,
  user_id TEXT,
  item_id TEXT,
  PRIMARY KEY (id),
  FOREIGN KEY (user_id) REFERENCES users (id),
  FOREIGN KEY (item_id) REFERENCES items (id)
);

优点:

  • 数据库为您处理外键关系。
  • 任何行中都没有额外的NULL列值。

缺点:

  • 您最终会创建大量表格,每种关系类型都有一个。

一对列方法似乎很普遍,但这意味着数据库不再自动为您处理外键关系,这似乎是一个非常大的缺点 - 如{{1}不再是一种选择。对我而言,这似乎是一个负面因素,使其成为一个合法的选择。

许多表方法似乎也很普遍,对于“成员资格”用例,这是有道理的。但对于其他用例,例如“事件”(可以创建与数据库中的任何对象相关的事件,而不是预约束列表),那么拥有如此大量的表似乎不实用。

XOR Columns 方法看起来并不普遍,或者至少我找不到关于它的信息,但感觉就像一个很好的平衡,仍然让数据库做了所有这项工作没有增加很多表格。

XOR列方法是否存在明显问题?

有推荐的解决方法吗?

0 个答案:

没有答案