【问题标题】:PostgreSQL View on a JSONB field object _array_ (with indexing)JSONB字段对象_array_上的PostgreSQL视图(带索引)
【发布时间】:2019-12-11 07:10:36
【问题描述】:

问题

如何基于 JSONB 字段对象数组 制作PostgreSQL 视图,并带有适当的索引?下面的例子。

  1. 从概念上讲,在使用视图和 JSONB 数组时应如何应用索引?
  2. 创建相关索引的正确语法是什么?
  3. 是否为示例视图提供了构建此用例视图的正确/最佳方式?

示例

表格

CREATE TABLE "ProductLists"
(
    id uuid NOT NULL DEFAULT gen_random_uuid(),
    listName text NOT NULL
    productIds jsonb NOT NULL DEFAULT '[{ productId:0 }]'::jsonb,
)

视图(可更改)

有以下观点:

SELECT "ProductLists".id AS listId,
    jsonb_array_elements("ProductLists".productIds) ->> 'productId'::text AS productId
   FROM "ProductLists";

因素

  • JSONB Root 是一个数组,而不是一个对象(在大多数索引示例中并非如此)
  • 可能会有数百万个 ProductList 项
  • 每个列表中的 productId 数量通常少于 100 个
  • 该表将同时具有高读取和写入
  • 视图 SQL 示例可能适合也可能不是最佳用途,并且可以更改

感谢您的任何意见!

【问题讨论】:

  • 最有效的方法是规范化你的数据模型。 blog.2ndquadrant.com/…
  • 与你的问题无关,但是:你真的应该避免那些可怕的引用标识符。他们的麻烦比他们的价值要多得多。 wiki.postgresql.org/wiki/…
  • 您打算在该表上运行什么样的查询?什么样的条件?
  • @a_horse_with_no_name,感谢您的回复。关于引用标识符的好提示。 RE:场景和查询类型。基本上,我需要维护许多有序的产品列表。顺序很重要。以前我使用带有 productId、listId 和 listOrder 字段的映射表。但是,列表经常更改。长列表的重新排序操作可能导致需要更新 100 行中的 listOrder 值。我正在考虑使用 JSONB 字段来避免这种情况。一个有序列表,整齐地存储在一个字段中。
  • @a_horse_with_no_name - (不来自上述评论)。最常见的查询只是获取列表的 productIds。 JSONB 解决方案在这里效果很好。但是,不常见的操作是删除产品 - 在这种情况下,需要识别给定 productId 的所有列表。这就是我在这里尝试解决的用例,通过索引 JSONB 字段并添加视图

标签: postgresql indexing view jsonb


【解决方案1】:

https://www.postgresql.org/docs/current/datatype-json.html

{
    "tags": [
        "enim",
        "aliquip",
        "qui"
    ]
}

-- Find documents in which the key "tags" contains key or array element "qui"
SELECT * FROM api WHERE jdoc -> 'tags' ? 'qui';

不过,通过适当使用表达式索引,上述查询可以 使用索引。如果在“标签”键中查询特定项目 很常见,定义这样的索引可能是值得的:

CREATE INDEX idxgintags ON api USING gin ((jdoc -> 'tags'));

现在,WHERE 子句 jdoc -> 'tags' ? 'qui'

将被识别为 可索引运算符? 的应用 索引表达式jdoc-> 'tags'

所以如果你要改变结构的话

'[{ "productId":0 }, { "productId":0 }]'

'{"productIds": ["0", "1"]}'

甚至

'{"products": {"0": {"title": "aaa"}, "1": {"title": "bbb"}}}'

你可以建立适当的索引

【讨论】:

    【解决方案2】:

    jsonb 列上的 GIN 索引将支持 several JSON operators。其中之一是 @> 运算符,它也适用于 JSON 数组。

    以下索引:

    create index on product_list using gin (product_ids);
    

    可能会使用上述索引的查询如下所示:

    select *
    from product_list
    where product_ids @> '[{"productId": 42}]'::jsonb;
    

    您建议的视图无法使用索引,因为 JSONB 列不是视图的一部分,而这对于向下推 JSON 列上的​​条件是必要的。

    在视图中使用索引的唯一方法是在其中包含 JSON 列:

    create view normalized_list
    as
    SELECT pl.id AS list_id,
           t.product_id, 
           pl.product_ids
    FROM product_list pl
       CROSS JOIN jsonb_array_elements(pl.product_ids) ->> 'id' AS t(product_id)
    ;
    

    这样的查询:

    select id, product_Id
    from normalized_list
    where product_ids @> '[{"id":42}]'::jsonb;
    

    将使用 GIN 索引。


    请注意,如果您希望以非规范化方式存储 ID,则本机整数数组 (product_ids int[]) 会更高效,并且会使表格更小

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-15
      • 1970-01-01
      • 2017-06-27
      • 2015-04-13
      • 1970-01-01
      • 2016-03-06
      • 2021-04-23
      相关资源
      最近更新 更多