【问题标题】:jsonb and primary/foreign keys: which performs better in PostgreSQL?jsonb 和主/外键:哪个在 PostgreSQL 中表现更好?
【发布时间】:2015-02-27 01:21:05
【问题描述】:

我正在考虑将 PostgreSQL 的 jsonb 列类型用于主要用作 REST-ful JSON API 的新后端项目。我相信 PostgreSQL 的 jsonb 非常适合这个项目,因为它会给我 JSON 对象,而无需在后端进行转换。

但是,我了解到 jsonb 数据类型在添加键时会变慢,并且我的架构将需要使用主键和外键引用。

我想知道是否在它们自己的列中包含主键/外键(以标准关系数据库方式),然后为其余数据设置一个 jsonb 列是否有益,或者这会导致问题(是否现在还是以后)?

简而言之,会:

table car(id int, manufacturer_id int, data jsonb)

表现好于或差于:

table car(data jsonb)

尤其是在频繁查找外键时?
从性能或架构的角度来看,第一个是否有缺点?

【问题讨论】:

  • 你为什么要使用jsonb?听起来您的架构或多或少是固定的,并且将行转换为 JSON 应该足够快,您无需担心。
  • 好问题:我对我的架构需要的关系有一个很好的了解,但此时我对每个表需要的信息没有具体的了解,虽然每次我弄清楚这一点时,我都可以进行数据库迁移,我认为使用 jsonb 可以让我获得良好的性能以及一种快速添加内容的简单方法。也许稍后,一旦我对所需数据有了更具体的了解,我就可以回到良好的关系设置。但这与问题的重点无关,即:一个比另一个表现更好/更差吗?
  • 但是无论如何你将不得不做一堆迁移来重写你的 JSON,这里和那里的几个 ALTER TABLE 不应该是可怕的,如果他们然后重写你所有的数据和代码跟踪一个不断变化的模式应该更可怕。就回答问题而言,首先您需要提出正确的问题。我认为你需要先弄清楚你的数据是什么样子,然后再开始到处乱扔数据。如果您认为您打算先行一步,然后返回并重新设计数据库,那么您几乎可以肯定是错误的,它不会发生。
  • 如果我错了,请纠正我,但它接受任何 JSON 字符串的 jsonb 列类型的全部目的不是吗?因此,如果我想添加car_color_hex_code 或其他随机属性,我只需将其添加到 json 字符串并将其存储在 jsonb 列中,对吗?无需迁移。至于你的第二点:我怎样才能更好地以正确的方式提出这个问题?我只是想知道主键/外键是否会在 jsonb 列或它自己的列中更好地工作,以及将它放在外面会导致什么后果。有没有更好的方法来问这个问题?
  • JSON 是(IMO)用于非结构化或松散结构化数据的,您可以将任何您想要的 JSON 放入 jsonb,但这并不意味着您应该这样做。我认为你甚至不能在jsonb 中拥有一个带有源或目标的 FK,对于 PK 也是如此。使用jsonb 可能对您的“随机属性包”有意义,但您不会有太多的完整性约束来帮助您保持数据的清洁和合理。除非你有真实数据的基准测试,否则性能问题很难回答。

标签: postgresql database-design foreign-keys jsonb


【解决方案1】:

PRIMARY KEYFOREIGN KEY 约束中涉及的所有值必须存储为专用列(最好以标准化形式存储)。约束和引用不适用于嵌套在 json / jsonb 列中的值。

至于其余数据:视情况而定。将它们放在jsonb(最好是)值中具有众所周知的存储非结构化文档类型数据的优点和缺点。

对于所有或大多数行都存在的属性,将它们存储为单独的列很可能会更好(更快、更干净、更小的存储空间)。更简单的索引和更简单的查询也是。即使新的jsonb 具有amazing index capabilities,索引专用列仍然更简单/更快。

对于很少使用或动态出现的属性,或者如果您想存储和检索 JSON 值而不需要在数据库中进行太多处理,请查看 jsonb

对于基本的EAV structures,主要是字符数据,没有嵌套,也没有与 JSON 的连接,我会考虑hstore。还有xml(更复杂和冗长)和json 数据类型(大部分已被jsonb 取代),它们正在失地。

【讨论】:

  • 是的......“这取决于”。此处未解决的一个问题是,如果您更新 jsonb 值的 any 子字段,则必须重写 整个元组 并且必须更新指向它的任何/所有索引。如果您已将数据分解为具有 pk/fk 关系的实体,则情况不再如此,您可以仅插入/更新/删除其中的一部分,而无需强制重写整个内容。
  • @CraigRinger 在 postgres 9.5 中仍然如此吗?我在阅读发布文档中的本节后问wiki.postgresql.org/wiki/…
  • @t1m0 是的。它是 TOAST 离线存储和 MVCC 所固有的。 PostgreSQL 现在可以修改 jsonb 对象,而不必完全解构和重建它,但这是内存修改。它仍然必须从磁盘中读取整个内容,并且仍然必须将整个新的修改版本再次写入新元组。
【解决方案2】:

哪个表现更好?取决于使用情况。当您比较 SQL(关系)和 NoSQL(KeyValue 或文档)数据库时,这是同一个问题。对于某些用例,NoSQL 数据库的性能非常好,而对于其他用例则不然。

关系概念(规范化架构)针对典型的 OLTP 使用进行了优化 - 70% 读取/30% 写入、多用户、大量更新、报告计算、一些即席查询。关系概念比较广泛通用..具有非常广泛的可用性(证据,会计,处理支持,...)。通常到处都不会太糟糕。

很明显,因此专门的数据库(文档、键值、图表)在专门的用例上可以明显更好(快一个订单)。但是它们的使用范围要窄得多。当您没有优化用例时,性能可能会很差。

其他问题是数据库大小 - 记录数。生产数据库的性能差异可能在数十万行中非常显着。对于一些较小的数据库,影响可能不大。

Postgres 是关系数据库,我的偏好是对数据库中的所有重要数据使用规范化模式。当你用得好时,它的速度非常快。非关系类型非常适合某些模糊数据(HStore、JSON、XML、Jsonb)——它明显优于 EAV 模式(在更大的数据上表现更差)。

如果您需要做一些重要的决定,请准备原型,填写预期数据(3 年)并检查您系统中一些重要查询的速度。注意:对这些基准的强烈影响使用了 hw、current load、current sw。

【讨论】:

    猜你喜欢
    • 2016-03-05
    • 2023-03-14
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    相关资源
    最近更新 更多