有两个表:
授权联系人(auth_contacts
):
(
userid varchar
contacts jsonb
)
contacts
包含一系列具有属性{contact_id, type}
discussion
:
(
contact_id varchar
discussion_id varchar
discussion_details jsonb
)
表auth_contacts
至少有100k记录,因此非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?
当我尝试这个时,它不会产生任何结果。
在搜索网络时,这似乎是一项非常麻烦的任务?
答案 0 :(得分:9)
你粗暴的方式"实际上并没有工作。这是另一种粗糙的方式:
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);
详细说明:
这一切都很吸引人,但这里的问题是关系模型。你的主张:
因此根据它不适合使用非JSONB类型 将记录数量增加一倍或三倍。
与正好相反。它将无意义包装为将表连接到JSON文档类型所需的ID。使用多对多关系规范化表,并将您在DB中使用的所有ID实现为具有适当数据类型的单独列。基本信息: