目前,我正在针对具有800万以上行的JSONB表编写查询。如何以最有效的方式从parent
和friends
对象进行查询?
查询(Postgres 9.6):
select distinct id, data->>'_id' jsonID, data->>'email' email, friends->>'name' friend_name, parent->>'name' parent
from temp t
CROSS JOIN jsonb_array_elements(t.data->'friends') friends
CROSS JOIN jsonb_array_elements(friends->'parent') parent
where friends ->> 'name' = 'Chan Franco'
and parent->>'name' = 'Hannah Golden'
示例DDL(带有数据):https://pastebin.com/byN7uyKx
答案 0 :(得分:1)
与规范化的关系设计相比,您的规则结构化数据将更干净,更小和更快。
也就是说,要使设置更快,(如果不快于具有匹配索引的标准化设计),请在表达式data->'friends'
上添加 GIN索引:
CREATE INDEX tbl_data_friends_gin_idx ON tbl USING gin ((data->'friends'));
然后使用包含运算符 WHERE
向我们的查询中添加匹配的@>
子句:
SELECT DISTINCT -- why DISTINCT ?
id, data->>'_id' AS json_id, data->>'email' AS email
, friends->>'name' AS friend_name, parent->>'name' AS parent
FROM tbl t
CROSS JOIN jsonb_array_elements(t.data->'friends') friends
CROSS JOIN jsonb_array_elements(friends->'parent') parent
WHERE t.data->'friends' @> '[{"name": "Chan Franco", "parent": [{"name": "Hannah Golden"}]}]'
AND friends->>'name' = 'Chan Franco'
AND parent ->>'name' = 'Hannah Golden';
db <>提琴here
巨大 的不同之处:借助索引,Postgres现在可以在之前识别匹配的行,而不再嵌套每个嵌套的“朋友”整个表中的数组。只有在 在基础表中标识了匹配的行之后,jsonb_array_elements()
才会被调用,并保留带有合格数组元素的结果行。
请注意,搜索表达式必须是有效的JSON,且与JSON数组data->'friends'
的结构匹配-包括括号[]
。但请忽略所有不应用作过滤器的键/值对。
相关:
我避免使用表名temp
,因为这是一个SQL关键字,可能会导致混乱的错误。改用名称tbl
。