Dmi*_*tri 5 postgresql database-design inheritance subtypes
这似乎是一个很常见的场景:几种类型都构成相同的子类型。
这通常看起来像这样:
-- 'name' is unique per parent record
CREATE TABLE sometype (
sometype_id serial PRIMARY KEY,
name text
);
CREATE TABLE foo (foo_id serial PK);
CREATE TABLE bar (bar_id serial PK);
CREATE TABLE foo_sometype (
foo_id int4,
sometype_id int4
);
CREATE TABLE bar_sometype (
bar_id int4,
sometype_id int4
);
Run Code Online (Sandbox Code Playgroud)
这很好,但查询起来很麻烦。我认为这可能更清洁:
-- 'name' is unique per parent record
CREATE TABLE sometype (
name text
);
CREATE TABLE foo_sometype (
foo_id int4
) INHERITS(sometype);
CREATE TABLE bar_sometype (
bar_id int4,
) INHERITS(sometype);
Run Code Online (Sandbox Code Playgroud)
我喜欢这个:
USING)不过,这似乎是继承的一种非典型用法。
有什么理由不这样做?
论继承的“不足”
请注意,Pg 继承的标准警告仅在使用表继承直接建模类继承时才相关,这不是我在这里所做的。事实上,为了让它工作,我需要继承来表现它的行为方式。
我几乎希望他们将其称为“继承”以外的东西,因为这种行为非常合乎逻辑,而“缺点”仅与一个用例相关。
优于手动复制表结构
正如 Evan 指出的那样,我可以手动创建与我描述的完全一样的 'foo_sometype' 和 'bar_sometype',但我认为继承结构有几个显着的好处:
因此,作为一个人为的例子,Foo 和 Bar 可能有一个 HasSomeTypeList 特征,它抽象了所有“sometype”操作,并且知道两个表都可以映射到 SomeType 类。
表示 Foo/Bar 关系,无论是建模为特征还是继承,都是这里的最终目标。
顺便说一句,对于天真的用户/查询编写者——他们不希望进行架构更改——这两种方式看起来是一样的。
继承是我不会接触的功能之一。AFAIK,它在内部用于某些容量的复制和分区。我不确定它是否是为了最终用户使用而设计的。
文档涵盖了CAVEAT 部分中的一些缺点(下面很重要)。
这些缺陷首先在 1996 年发布的7.3 文档中提到,尽管它们在继承实施后就存在了
这个缺陷可能会在未来的某个版本中得到修复。
唯一的变化是使2010 年发布的8.0 文档中的缺陷更加明确和详细。
这些缺陷可能会在未来的某个版本中得到修复,但同时在决定继承是否对您的问题有用时需要相当小心。
祝你好运,等待未来的发布。而且,您谈论的某些功能并不是构图独有的,
这与制作sometype属性列表并直接链接到它有什么不同?
CREATE TABLE sometype (sometype_name text PRIMARY KEY);
CREATE TABLE foo (foo_id serial PRIMARY KEY);
CREATE TABLE foo_sometype (
foo_id int REFERENCES foo,
sometype_name text REFERENCES sometype,
PRIMARY KEY ( foo_id, sometype_name )
);
Run Code Online (Sandbox Code Playgroud)
现在,你甚至不必加入foo_sometype到sometype得到sometype.sometype_name。
撇开所有这些问题不谈,即将发布的 PostgreSQL 10 表分区问题变得更糟
不允许多重继承,分区和继承不能混用
那你要继承吗?放弃分区,它实际上具有真正的规划器优势。
唉,ALTER TABLE它的注释中也列出了很多缺点,
如果表有后代表,则不允许在父表中添加、重命名或更改列的类型,或重命名继承的约束而不对后代进行相同的操作。也就是说,ALTER TABLE ONLY 将被拒绝。这可确保后代始终具有与父项匹配的列。[...] 递归 DROP COLUMN 操作将删除后代表的列,仅当后代不从任何其他父项继承该列并且从未对该列进行独立定义时。非递归 DROP COLUMN(即 ALTER TABLE ONLY ... DROP COLUMN)永远不会删除任何后代列,而是将它们标记为独立定义而不是继承。[...] TRIGGER、CLUSTER、OWNER 和 TABLESPACE 操作永远不会递归到后代表;那是,他们总是表现得好像只被指定了一样。仅对未标记为 NO INHERIT 的 CHECK 约束递归添加约束。
我认为没有多少人使用继承。我从未在野外见过它。db 中的继承增加了学习曲线,一些功能最好单独保留。您不必为它们找到应用程序。
您可能会发现Stack Overflow 上的这篇文章很有用,“何时在 PostgreSQL 中使用继承的表?”。
小智 6
提到的缺陷不是不使用继承的理由!继承在这里的工作类似于具有独立对象的类继承。您可能有一个类/表“水果”和一个类/表“苹果”和“橙子”。由于苹果和橙子从水果继承了它们的元定义,因此您可以通过水果获取它们。然而,它们是独立的类,具有独立的枚举,还有什么你可以期待......
如果您确实需要防止冲突:在主表上定义触发器或检查/外键(不包含)。
但是请不要因为您对 PostgreSQL 中继承的工作方式不满意而阻止人们使用它!独立的子类或表都很棒!如果你需要一些依赖 - 以你需要的方式实现它。有很多很好的教程,包括官方文档。这是另一个例子:继承——爱 PostgreSQL 的另一个理由。
尽管可能存在主键冲突(我的父表没有定义主键,而且我的模型不需要它),但我也在我的一个项目中使用了继承。
还有一些方法可以使用继承来提高性能,而不仅仅是 ORM。
难不等于坏。