何时在PostgreSQL中使用继承表?

时间:2010-06-19 06:04:50

标签: postgresql

在哪些情况下你应该使用继承表?我试图非常简单地使用它们,并且继承在OOP世界中似乎并不像。

我认为它的工作原理如下:

users,其中包含所有用户级别所需的所有字段。表格如moderatorsadminsbloggers等,但字段从父级检查 。例如users有电子邮件字段,并且继承bloggers现在也有,但它同时对usersbloggers都不是唯一的。即。就像我在两个表中添加电子邮件字段一样。

只有我能想到的用法是通常使用的字段,例如 row_is_deleted created_at modified_at 。这是继承表的唯一用法吗?

7 个答案:

答案 0 :(得分:98)

在postgres中使用表继承有一些主要原因。

让我们说,我们有一些统计所需的表格,每个月都会创建和填充:

statistics
    - statistics_2010_04 (inherits statistics)
    - statistics_2010_05 (inherits statistics)

在此示例中,每个表中有2.000.000行。每个表都有一个CHECK约束,以确保只匹配月份的数据存储在其中。

那么是什么让继承成为一个很酷的功能 - 为什么拆分数据很酷?

  • 性能:在选择数据时,我们SELECT * FROM statistics WHERE date BETWEEN x和Y,而Postgres只使用表,这是有意义的。例如。 SELECT * FROM statistics WHERE date BETWEEN'2010-04-01'and'2010-04-15'仅扫描表statistics_2010_04,所有其他表格都不会被触及 - 快!
  • 索引大小:我们在列日期没有大胖表和大胖指数。我们每个月都有小表,索引很小 - 读取速度更快。
  • 维护:我们可以在每个月的表上运行vacuum full,reindex,cluster而不锁定所有其他数据

要正确使用表继承作为性能助推器,请查看postgresql手册。 您需要在每个表上设置CHECK约束以告知数据库,您的数据被分割(分区)在哪个键上。

我大量使用表继承,特别是在按月分组存储日志数据时。提示:如果存储永远不会更改的数据(日志数据),则使用CREATE INDEX ON()WITH(fillfactor = 100)创建或索引;这意味着索引中不会保留更新空间 - 索引在磁盘上较小。

更新:  fillfactor默认值为100,来自http://www.postgresql.org/docs/9.1/static/sql-createtable.html

表的fillfactor是介于10和100之间的百分比.100(完全打包)是默认值

答案 1 :(得分:30)

“表继承”表示与“类继承”不同的东西,它们用于不同的目的。

Postgres是关于数据定义的。有时真正复杂的数据定义。 OOP(在常见的Java颜色的意义上)是关于在单个原子结构中对数据定义的从属行为。 “继承”一词的目的和意义在这里有很大的不同。

在OOP领域,我可能会定义(这里语法和语义非常松散):

import life

class Animal(life.Autonomous):
  metabolism = biofunc(alive=True)

  def die(self):
    self.metabolism = False

class Mammal(Animal):
  hair_color = color(foo=bar)

  def gray(self, mate):
    self.hair_color = age_effect('hair', self.age)

class Human(Mammal):
  alcoholic = vice_boolean(baz=balls)

这个表可能如下:

CREATE TABLE animal
  (name       varchar(20) PRIMARY KEY,
   metabolism boolean NOT NULL);

CREATE TABLE mammal
  (hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL,
   PRIMARY KEY (name))
  INHERITS (animal);

CREATE TABLE human
  (alcoholic  boolean NOT NULL,
   FOREIGN KEY (hair_color) REFERENCES hair_color(code),
   PRIMARY KEY (name))
  INHERITS (mammal);

但这些行为在哪里?他们不适合任何地方。这不是数据库世界中讨论的“对象”的目的,因为数据库涉及数据,而不涉及过程代码。您可以在数据库中编写函数来为您进行计算(通常是一个非常好的主意,但不是真正符合这种情况的东西)但是函数与方法不同 - 正如您所说的OOP形式所理解的方法关于故意不那么灵活。

还有一点需要指出继承作为原理图设备:从Postgres 9.2开始,无法同时在所有分区/表系列成员中引用外键约束。您可以编写检查来执行此操作或以其他方式绕过它,但它不是内置功能(它归结为复杂索引的问题,实际上,没有人编写了使自动化所需的位)。为此目的而不是使用表继承,通常在数据库中更好地匹配对象继承是对表进行原型扩展。像这样:

CREATE TABLE animal
  (name       varchar(20) PRIMARY KEY,
   ilk        varchar(20) REFERENCES animal_ilk NOT NULL,
   metabolism boolean NOT NULL);

CREATE TABLE mammal
  (animal      varchar(20) REFERENCES animal PRIMARY KEY,
   ilk         varchar(20) REFERENCES mammal_ilk NOT NULL,
   hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL);


CREATE TABLE human
  (mammal     varchar(20) REFERENCES mammal PRIMARY KEY,
   alcoholic  boolean NOT NULL);

现在我们有一个关于我们可以可靠地用作外键引用的动物实例的规范参考,并且我们有一个“ilk”列引用xxx_ilk定义表,该表指向“下一个”表扩展数据(或表示如果类型是泛型类型本身则没有)。针对这种模式编写表函数,视图等是非常容易的,当你求助于OOP风格的类继承来创建对象类型族时,大多数ORM框架在后台完成这类工作。

答案 2 :(得分:5)

只要您不需要在父表上创建外键,就可以在OOP范例中使用继承。例如,如果您有一个存储在车辆表中的抽象类车辆和从其继承的表车,则车辆表中将显示所有车辆,但车辆表上的驾驶员表中的外键将不匹配记录。

继承也可以用作partitionning工具。当你有永远成长的表(日志表等)时,这尤其有用。

答案 3 :(得分:3)

继承的主要用途是用于分区,但有时它在其他情况下很有用。在我的数据库中,有许多表只在外键中有所不同。我的“抽象类”表“image”包含一个“ID”(它的主键必须在每个表中)和PostGIS 2.0栅格。诸如“site_map”或“artifact_drawing”之类的继承表具有外键列(“site_map”的“site_name”文本列,“artifact_drawing”表的“artifact_id”整数列等)以及主键和外键约束;其余部分继承自“图像”表。我怀疑将来可能不得不在所有图像表中添加“描述”列,这样可以省去很多工作而不会产生实际问题(好吧,数据库运行速度可能会慢一点)。

编辑:另一个好用:使用two-table handling of unregistered users,其他RDBMS在处理这两个表时遇到问题,但在PostgreSQL中它很容易 - 当你没有对继承的数据感兴趣时,只需添加ONLY “未注册用户”表。

答案 4 :(得分:2)

我对继承表的唯一体验是分享。它工作正常,但它不是PostgreSQL中最复杂和易于使用的部分。

上周我们看到了同样的OOP问题,但是Hibernate遇到了太多问题(不喜欢我们的设置),所以我们没有在PostgreSQL中使用继承。

答案 5 :(得分:0)

当表之间有超过1对1的关系时,我使用继承。

示例:假设您要存储具有属性x,y,旋转,缩放的对象地图位置。

现在假设您有几种不同类型的对象要在地图上显示,并且每个对象都有自己的地图位置参数,并且地图参数永远不会被重复使用。

在这些情况下,表继承对于避免维护非标准化表或必须创建位置ID并将其交叉引用到其他表非常有用。

答案 6 :(得分:-3)

尽可能少地使用它。这通常意味着从来没有,它沸腾到一种创建违反关系模型的结构的方式,例如通过打破信息原则和创建包而不是关系。

相反,使用表分区与适当的关系建模相结合,包括进一步的正常形式。