【问题标题】:Indexing only an attribute on a json array - Postgres仅索引 json 数组上的属性 - Postgres
【发布时间】:2020-05-30 06:27:07
【问题描述】:

我有一个带有名为“data”的 jsonb 字段的表,其内容如下:

{
  customerId: 1,
  something: "..."
  list: [{ nestedId: 1, attribute: "a" }, { nestedId: 2, attribute: "b" }]
}

我需要根据它的 'nestedId' 属性检索整行,注意该字段在一个数组中。

检查查询计划后,我发现我可以从索引中受益。所以我补充说:

CREATE INDEX i1 ON mytable using gin ((data->'list') jsonb_path_ops))

根据我从文档中了解到的情况,这会为“列表”中的值创建索引项,该解决方案解决了我的问题。

为了完成,请按照我可以用来检索数据的查询

SELECT data FROM mytable where data->'list' @> '[{"nestedId": 1}]'

不过,我想知道是否有更优化的索引可以做。例如,是否可以仅为“nestedId”字段创建索引?

【问题讨论】:

  • "...我想知道是否有更好的方法来解决..." - 如果可能的话,考虑完全不使用 JSON(或者至少对于您遇到的那部分),而是适当规范化关系模式。
  • @stickybit 我认为我没有正确表达自己,没有解释约束。假设数据“结构”是相同的。我更新了问题。
  • 我认为没有更高效的 JSON 索引可以使用。众所周知,对随机数组元素的访问很难索引。

标签: arrays postgresql indexing jsonb


【解决方案1】:

您可以使用功能索引仅对数值进行索引,而不能对键进行索引。您可能需要创建一个辅助函数来执行此操作。

create function jsonb_objarray_to_intarray(jsonb,text) returns int[] immutable language sql as 
  $$ select array_agg((x->>$2)::int) from jsonb_array_elements($1) f(x) $$;

create index on mytable using gin (jsonb_objarray_to_intarray(data->'list','nestedId'));

SELECT data FROM mytable where jsonb_objarray_to_intarray(data->'list','nestedId') @> ARRAY[3];

我是这样写的,所以这个函数可以在其他类似的情况下重用。如果您不关心它被重用,您可以通过将解引用和键值硬编码到函数中来使使用它的代码看起来更漂亮:

create function mytable_to_intarray(jsonb) returns int[] immutable language sql as 
  $$ select array_agg((x->>'nestedId')::int) from jsonb_array_elements($1->'list') f(x) $$;

create index on mytable using gin (mytable_to_intarray(data));

SELECT data FROM mytable where mytable_to_intarray(data) @> ARRAY[3];

现在,这些索引的创建时间确实比原来的要长,但它们的大小大约是原来的一半,而且查询速度至少一样快。更重要的是,planner 对选择性有更好的统计,因此在更复杂的查询中可能会提出更好的查询计划。

【讨论】:

    猜你喜欢
    • 2016-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多