查询嵌套在JSON数组中的数据的最有效方法?

时间:2018-11-06 19:50:25

标签: arrays postgresql database-design jsonb postgresql-performance

目前,我正在针对具有800万以上行的JSONB表编写查询。如何以最有效的方式从parentfriends对象进行查询?

查询(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

1 个答案:

答案 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