如何在postgresql中深度嵌套的jsonb属性上创建索引

问题描述 投票:0回答:1

我有一个名为 orders 的表,其中包含名为 data 的列,其数据类型为 jsonb,它看起来像这样

"data": [
  "items": [
   {"name": "Peter"},
   {"name": "John"}
  ]
]

这是检索唯一名称列表的查询:

    SELECT distinct NameList->'name' AS uniqueNames
FROM orders
         CROSS JOIN jsonb_array_elements(data) itemsData
         CROSS JOIN jsonb_array_elements(itemsData->'items') NameList
WHERE NameList != '[]'

这里,data还有很多其他信息,但我对items感兴趣。因此,如何在 NameList != '[]' 上创建索引?

postgresql indexing jsonb
1个回答
1
投票

如果您正在寻找性能,在 PostgreSQL 12+ 上

jsonpath
即使没有索引支持,也应该比这更快。 db<>fiddle 的演示:

select distinct jsonb_path_query(data,'$.data[*].items[*].name') 
from orders 
where data @? '$.data[*].items[*].name';

您可以通过让索引缩小应该检查的行来进一步改进,与上面的

where
相同:

create index on orders((data @? '$.data[*].items[*].name'));

您的问题有一些问题

  1. 您提供的

    jsonb
    值格式不正确。
    data
    是一个键,因此它需要位于一个对象中。我猜测它的值是一个数组,如它包含的方括号所示以及您在其上调用
    jsonb_array_elements()
    的事实。
    items
    也是一个键,因此它需要位于对象中,作为
    data
    数组的元素。所以你缺少一对外部大括号,以及另一对
    items
    :

    {   "data": [
            {   "items": [
                    {   "name": "Peter"},
                    {   "name": "John" }
                ]
            }
        ]
    }
    
  2. 查询在语法或逻辑上无效:

    1. 您为
      jsonb_array_elements()
      的结果集设置了别名,但未命名其字段/列,因此您的引用是其整个记录而不是其中的内容:
      CROSS JOIN jsonb_array_elements(data) itemsData
      CROSS JOIN jsonb_array_elements(itemsData->'items') NameList
      
      为结果集定义一个名称其字段名称,以便能够像这样使用它:
      CROSS JOIN jsonb_array_elements(data) AS elements1(itemsData)
      CROSS JOIN jsonb_array_elements(itemsData->'items') AS elements2(NameList)
      
    2. 如果您检查了一个空的
    3. NameList != '[]'
       数组,那么 
      jsonb
      将会起作用,但您刚刚使用了一个函数将其打开并分解为单个元素;在上述修复之前,
      NameList
      是保存单个数组元素的记录。修复后就是数组元素了。我认为
      (itemsData->'items')
      是你要检查的数组
      CROSS JOIN jsonb_array_elements(data) AS elements1(itemsData)
      CROSS JOIN jsonb_array_elements(itemsData->'items') AS elements2(NameList)
      WHERE (itemsData->'items') != '[]'
      
      但这个条件并没有真正的帮助:如果该数组为空,该函数无论如何都不会产生任何内容,因此无需将其过滤掉。它也不能用于估计可以跳过表的哪些行,因为为了建立这一点,它必须到达每行的深度,并且因为这是通过设置返回函数执行的,所以您不能构建与此条件相对应的表达式索引(见下文)。
  3. jsonb_array_elements()
    是一个集合返回函数,因此不能在 表达式索引中使用:

    ERROR:  set-returning functions are not allowed in index expressions
    

    不过,由于您的数组检查可以修复,因此可以使用类似的修复来为您提供一些可用的索引:

    create index on orders((data->'data')) 
    where (jsonb_array_length(data->'data')>0);
    

    如果您的

    data
    有时为空并且您经常检查其内容,这可能会有所帮助,但您似乎担心的是其中的
    items
    列表,这实际上并没有帮助。

话虽这么说,标准化结构将更容易索引和查询,并且更轻、更快。

© www.soinside.com 2019 - 2024. All rights reserved.