是否有关于何时规范化数据库或仅使用复合类型和数组的指南?
使用数组和复合类型时,我只能使用一个表。我也可以规范化数据库并使用几个表和连接。
您如何确定最佳选项?
答案 0 :(得分:10)
大多数时候,坚持正常化。除此之外,保持数据库相当规范化有助于锁定粒度。例如,如果您有一个“父”对象,其中包含两个数组,则您不能拥有同时添加/更新/修改数组成员的事务。如果他们是常规的边桌,你可以。 (如果您想要序列化行为),在更新子对象之前,您仍然可以SELECT ... FOR UPDATE
父行。
更新数组以添加/替换/删除值是很昂贵的,因为PostgreSQL必须将整个元组重新编译为中的MVCC更新。 (它有一些TOAST技巧可以帮助,但不是吨)。嵌入行中的Ditto复合类型。
充满数组和复合的大行意味着较慢的表扫描,这意味着对常用值的读取速度较慢。
IIRC您无法将外键定义为复合类型的字段,因此您会发现自己正在解决这个问题,或者放弃参考完整性,这样才能获得好处。同上阵列(有was work to get foreign keys to arrays to work,但我认为它没有被评出)。
许多客户端驱动程序(PgJDBC,psqlODBC,psycopg2等等)对数组和组合都有不完整到不存在的支持,因此无论如何,您经常会将它们扩展为元组以进行客户端驱动程序交互。有些东西,比如复合类型的数组,使用它真的很痛苦。
大多数ORM,包括像Hibernate这样的常见ORM,完全不习惯使用除了最完全简单的最低公分母SQL特性之外的任何东西。迟早,某人会想要在你的数据模型中指出其中一个,此时会发出许多嚎叫和咬牙切齿的信息。 OTOH,不要容纳垃圾ORM,以避免使用能够大大改善数据模型和解决实际问题的功能 - 例如,如果您可以选择存储本地hstore
字段,或者使用一个EAV模式,考虑使用jstore
(或更好,在9.4中,json使用hstore功能)。
(反过来说,这意味着拥有最多“面向对象”程序的人通常拥有最纯粹的关系数据库,因为他们的工具很糟糕。)
像报告生成工具这样的东西同样会遇到复合材料和数组,所以你经常会创建视图来为数据库呈现标准化的外观。然后ON INSERT OR UPDATE OR DELETE ... DO INSTEAD
触发视图以启用写入。在这一点上,它变得丑陋。
我个人建议保留复合材料,以便将某些东西建模为“类型”是合乎逻辑的。例如,假设您的数据模型要求您跟踪其原始时区中的时间戳。没有内置类型(不,这不是“带时区的时间戳”的作用,尽管名称,感谢SQL委员会),因此您可以创建一个存储(timestamp without time zone, tzname)
的复合类型并在你的数据模型。
同样,我倾向于在查询中大量使用数组,但在数据模型中却不多。当你想要故意对某些东西进行异常化以获得性能时,它们很有用,但这通常是在物化视图或类似视图中完成的。即使它是对主数据模型的改变,它也是你应该根据适当的性能评估做的事情,而不仅仅是“优化”你不知道的东西还很慢。