如何在 postgresql 中实现 SET?

Posted

技术标签:

【中文标题】如何在 postgresql 中实现 SET?【英文标题】:How do I implement a SET in postgresql? 【发布时间】:2016-09-22 00:53:17 【问题描述】:

在postgresql 9.5 docs 中说

当涉及到许多键或元素时,JSON 对象比数组更适合用于测试包含或存在,因为与数组不同,它们在内部针对搜索进行了优化,并且不需要进行线性搜索。

我没有在 postgresql 中使用过 json 或 jsonb。我打算使用int[] 通过使用ANY 检查值是否在列表中来实现一个集合。现在我正在考虑使用 jsonb。是否可以将值添加到数组中,或者这可能是一项昂贵的操作?如何添加元素? (select '["a", "b"]'::jsonb || '["c", "d"]'::jsonb) 似乎是一个错误)可疑大小将在 500-10K 的整数(4 字节)之间。

【问题讨论】:

【参考方案1】:

文档暗示您可以将 21412,32356,754432 之类的集合存储为以下 jsonb 对象:

"21412": null, "32356": null, "754432": null

请注意,我们已将整数转换为对象中必须为字符串的键。因此,如果您将上述对象存储在表jsonb 类型为jsonb 的列s 中,那么您可以搜索集合中包含值的所有行,如下所示:

SELECT * FROM t WHERE s ? 3523::text;

可以按如下方式添加元素:

SELECT jsonb_set(s, array[35232::text], 'null'::jsonb)
FROM t
WHERE .......;

但请注意,以上可能是一个坏主意。这不是您应该在关系数据库中存储集合的方式。例如,考虑一下:每次向集合中添加一个元素(无论是jsonbinteger[] 还是其他),都必须重写整行。这将花费Θ(n) 时间加上插入所需的时间。另一个问题是,涉及来自 set 列的值的连接将更加困难。所以实现集合的正确方法是创建一个额外的表并为每个集合元素添加一行。

【讨论】:

另外值得指出的是,具有 500 个元素的 jsonb 值(或 int[],就此而言)大到足以触发 TOAST compression,所以我相信搜索将涉及一个 O(n) 的解压步骤,与类型的查找算法无关

以上是关于如何在 postgresql 中实现 SET?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PostgreSQL 中实现多对多关系?

如何在 Postgresql 中实现对复杂嵌套 JSONB 的全文搜索

如何在 jOOQ for MySQL 8 中实现 JSON_SET()

在PostgreSQL中实现按拼音汉字拼音首字母搜索的例子

PostgreSQL中实现更新默认值

如何使用 LINQ 在 NHibernate 3 中实现关键字搜索?