【问题标题】:Storing a group of ids in postgres在 postgres 中存储一组 id
【发布时间】:2016-03-12 03:00:24
【问题描述】:

我有一个主键 ID 为 (1,2,3) 的主表。我需要存储一个关系,它说 Book 1 是相似的 book 2 , book 3 。

需要的是我应该能够通过加入主表和这个关系表来找到类似的书。存储这个的最好方法是什么?

有两种方法。
第一种方法:

1,2
1,3
2,3
2,1
3,1
3,2

其次是使用 postgres 数组:

1 -> [2,3]
2 -> [3,1]
3 -> [1,2]

有什么好处和坏处?我们还缺少其他方法吗?

【问题讨论】:

  • 1NF, all data in columns should be atomic. 我会使用第一种方法,但一如既往地视情况而定。
  • 取决于其他什么。我了解第一种方法是传统 DBA 将采用的方式。但是如果我们在这种情况下使用数组,我们可能会失去什么?
  • 例如:更新/搜索/删除时可能需要使用数组运算符/函数。它可能比原子索引列慢。要与其他列连接,您需要先将其拆分等。像[2,2,2] 这样的数组中的值的唯一性是什么?
  • 好的,在这种特殊情况下,不会有任何原子操作,在初始插入之后,它总是只读数据。

标签: postgresql database-design


【解决方案1】:

优点和缺点。让我们从您的第一种方法是 1NF 而您的第二种方法不是我所理解的事实开始(可能是,见下文),以及含义是什么。基本上,您想从第一种方法开始,但请注意,在某些环境中,您必须执行第二种方法。

首先我们所说的原子是什么意思(之所以这么说是因为大多数人都搞错了):如果一个值引用了其域中的单个值,那么它就是原子的。这并不排除数组,但必须将数组视为适合原子值的(SQL 数组基本上是一个数学矩阵,它们是序数)。正如我在其他地方指出的那样,如果序数很重要,数组就是原子的。 top_five int[] 是原子的,ip_address int[] 也是原子的(将 IP 地址表示为 int 值的有序数组)。这意味着您可以对组执行您对单个元素无法执行的操作。一般来说,有两件事会破坏原子性:集合(如果我没记错的话,我认为你在这里尝试这样做,但是集合是无序的,而 sql 数组是有序的,所以如果你依赖于排序,这不适用)和案例其中一个数组成员在功能上依赖于另一个数组成员(此处不适用)。

所以我们在这里讨论的是 PostgreSQL 中第一范式与非第一范式设计的优缺点。此外,您在这里有一个明确的案例,因此可以不抽象地谈论这些,而是​​具体地谈论这些。

与大多数人不同的是,我对这两种方法都有亲身体验。我的建议是尽可能使用第一种方法,但如果需要,请理解第二种方法。

写入并发

您的第一种方法将支持比您的第二种方法更好的写入并发性(请参阅下面有关索引的更多信息)。如果您想在添加另一个相似性的同时删除一个相似性(都在同一本书中),则在第一种情况下事务不会相互锁定,但在第二种情况下它们会,因为两者都存储在同一行中并且需要等待行锁。

换句话说,甚至在我们开始讨论索引更新性能(这将是真正的开销)之前,第一个就可以更好地扩展写入。

数据完整性

您遇到的第二个问题是数据完整性。可以在第一种情况下定义独特的约束,而在第二种情况下不能很好地表达。你可以表达它们,但它们需要更多的维护工作。如果你走这条路,你需要更仔细地思考,你可能需要编写自定义函数来检查你需要验证的内容。这是更多的工作,它还增加了写入性能(远高于维护唯一索引的能力。

您还必须编写约束触发器来解决如果您删除一本书会发生什么。这可能是痛苦的和另一个维护问题。在我参与的项目使用这种方法的情况下,我们通常会接受某些数据会不一致,并构建能够容忍缺失链接的东西。这是一个非常重要的权衡,但有时是必要的。

索引和读取性能

PostgreSQL 有 GIN 索引,可以轻松索引数组成员。某些情况下的 GIN 索引是您选择第二种情况的唯一原因,但它们也并非没有成本。 GIN 索引更新成本高,但读取效率高。所以人们经常在 PostgreSQL 中打破自动性来做一些事情,比如存储标签数组。

如果您的数据很少更新,您有重大的读取性能问题,并且已经用尽了其他可能性,那么这种方法是有意义的,尤其是如果您可以容忍此处的孤立链接。

总体推荐

对于一般情况,您的第一个解决方案要好得多。在某些情况下,第二个效果更好,但是您需要注意,当您开始这样做时会弹出很多问题....

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-12
    • 2018-07-08
    • 2023-03-05
    • 2019-08-07
    • 2012-10-18
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多