使用 JSONB 列或另一个表来保存关系

ham*_*adi 2 postgresql database-design json many-to-many

我试图在这里彻底搜索,但没有找到任何答案。

我有一个 PostgreSQL 数据库,它有两个主表:

  • 文件
  • 用户

这两个表有不同的关系。用户可以:

  • 喜欢
  • 书签稍后阅读
  • 节省

... 一份文件。

问题是我应该如何保存这些关系?

根据我使用 MySQL 的经验,显而易见的方法是为这些多对多关系创建表,包含user_iddocument_id.

但是,因为我们使用PostgreSQL,它具有惊人的JSON支持,我们想也许更好的做法是有一个user_document表,其中包含user_iddocument_idJSON列包含所有关系。

JSON 将是这样的:

{
   'follow' : {'date' : 1523517140, 'doesFollow' : 't'}, 
   'bookmark' : {'date' : null, 'doesBookmark' : 'f'},
   ....
}
Run Code Online (Sandbox Code Playgroud)

我对 PostgreSQL 的经验几乎为零,我不知道在 JSONB 列上查询的性能。而且我不知道这种方法在 PostgreSQL 中是否有意义。但它似乎没问题,如果它没有任何问题,也许它比第一种正常方法更可取。

Erw*_*ter 5

jsonor jsonb(or xmlor hstore)这样的文档类型可以方便地存储文档。非常适合查询中具有不同键和很少更新且不太复杂的过滤条件的数据。在数据库中大量操作大文档将是一种反模式。

结构化数据通常以小增量写入,并且可能进行了大量搜索(就像您的情况一样),使用规范化设计效率更高 - 关于存储、性能、并发写入访问和数据完整性。因此手册中建议

JSON 数据在存储在表中时,与任何其他数据类型一样,需要遵守相同的并发控制注意事项。尽管存储大型文档是可行的,但请记住,任何更新都会获取整行的行级锁。考虑将 JSON 文档限制为可管理的大小,以减少更新事务之间的锁争用。理想情况下,JSON 文档应该每个都代表一个原子数据,业务规则规定不能合理地进一步细分为可以独立修改的较小数据。

使用一个或多个连接表实现您的 n:m 关系。您可以使用约束(PK、FK、UNIQUE、CHECK 等)来强制执行数据完整性,而对于文档类型,这些都不是很容易实现的。除非您对“喜欢”、“书签”等有明显不同的要求,否则我会倾向于使用一张桌子。

例子:

如果您不确定典型布局,以下是基础知识:

假设您的每个关系类型对于每个用户/文档组合只能使用一次。对于仅包含值的手(在您的情况下为 3),我将使用 1 字节"char"列作为查找表的 PK 来优化表和索引中的存储和性能。

CREATE TABLE reltype (
   reltype "char" PRIMARY KEY
 , relation_type text UNIQUE NOT NULL
);

INSERT INTO reltype(reltype, relation_type) VALUES
   ('l', 'like')
 , ('b', 'bookmark')
 , ('s', 'save');

CREATE TABLE user_doc (
   user_doc_id int PRIMARY KEY GENERATED ALWAYS AS IDENTITY
 , user_id     int REFERENCES users     ON UPDATE CASCADE ON DELETE CASCADE
 , document_id int REFERENCES documents ON UPDATE CASCADE ON DELETE CASCADE
 , reltype     "char" REFERENCES reltype NOT NULL DEFAULT 'l'
 , CONSTRAINT user_document_pkey UNIQUE(user_id, document_id, reltype)
);
Run Code Online (Sandbox Code Playgroud)

您始终可以将聚合数据导出为 JSON 文档。甚至有一个VIEWMATERIALIZED VIEW阅读像一张桌子。但不要管理单个大型 JSON 文档中的关系。