【问题标题】:Most efficient way to query data nested deep in JSON arrays?查询嵌套在 JSON 数组中的数据的最有效方法是什么?
【发布时间】:2019-04-10 06:21:43
【问题描述】:

目前,我正在编写针对超过 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

【问题讨论】:

  • 请将所有定义信息放入您的问题中。您的 Postgres 版本、表定义、示例值。 (冗长的测试用例可以留在外部站点 - 像 dbfiddle.uk 或 sqlfiddle.com 这样的小提琴站点会更适合这个。)
  • 一种更有效的方法是标准化您的模型。 blog.2ndquadrant.com/…
  • 感谢您的回复,我将寻求规范化此数据模型!

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


【解决方案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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多