有两个表:
授权联系人 ( auth_contacts
):
(
userid varchar
contacts jsonb
)
contacts
包含一组具有属性的联系人 {contact_id, type}
discussion
:(
contact_id varchar
discussion_id varchar
discussion_details jsonb
)
表
auth_contacts
至少有 10 万条记录,因此非 JSONB 类型是不合适的,因为它会使记录数量增加一倍或三倍。auth_contacts
的样本数据:userid | contacts
'11111' | '{"contact": [{"type": "type_a", "contact_id": "1-A-12"}
, {"type": "type_b", "contact_id": "1-A-13"}]}'
discussion
表有 500 万条奇数记录。我想加入
discussion.contact_id
(关系列)具有联系人 ID,其中一个 json 对象位于 auth_contacts.contacts
中的 json 对象数组中.一种非常粗糙的方法是:
SELECT *
FROM discussion d
JOIN (SELECT userid, JSONB_OBJECT_KEYS(a.contacts) AS auth_contact
FROM auth_contacts a) AS contacts
ON (d.contact_id = contacts.auth_contact::text)
这实际上是在运行时创建(内部 sql)用户 ID 与联系人 ID 表(这是我避免的,因此使用 JSONB 数据类型
对于具有大量记录的用户,此查询需要 26 秒以上的时间,这并不是很好。
尝试了其他几种方式:PostgreSQL 9.4: Aggregate / Join table on JSON field id inside array
但是应该有一种更清洁更好的方法,就像
加入
d.contact_id = contacts -> contact -> contact_id?
当我尝试这个时,它不会产生任何结果。在网上搜索时,这似乎是一项非常繁琐的任务?
最佳答案
概念证明
您的“粗暴方式”实际上不起作用。这是另一种粗略的方法:
SELECT *
FROM auth_contacts a
, jsonb_to_recordset(a.contacts->'contact') AS c(contact_id text)
JOIN discussion d USING (contact_id);
正如已经评论过的,您还可以使用 contains operator @>
来制定连接条件。 :SELECT *
FROM auth_contacts a
JOIN discussion d ON a.contacts->'contact'
@> json_build_array(json_build_object('contact_id', d.contact_id))::jsonb
而是使用 JSON 创建函数而不是字符串连接。看起来很麻烦,但如果支持功能性 jsonb_path_ops GIN 索引,实际上会非常快:CREATE INDEX auth_contacts_contacts_gin_idx ON auth_contacts
USING gin ((contacts->'contact') jsonb_path_ops);
细节:正确的解决方案
这一切都很有趣,但这里的问题是关系模型。您的主张:
hence making it non JSONB type is not appropriate according as it would double or triple the amount of records.
是 与正确的相反 .它是 废话 将表连接到 JSON 文档类型所需的 ID 包装起来。使用多对多关系规范化您的表,并将您在数据库中使用的所有 ID 实现为具有适当数据类型的单独列。基本:
关于sql - 使用 JSONB 列中的值连接表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31309362/