使用Postgres在json数组中索引对象元素

时间:2016-12-15 13:13:42

标签: sql arrays json postgresql

我有一个9.4 Postgres数据库,其中有一个包含jsonb字段的表。

json的结构看起来与此类似:

{
  name: 'customer1',
  age: 28,
  products: [{
    name: 'product1',
    price: 100
  }, {
    name: 'product2',
    price: 200
  }]
}

以下查询返回上述json就好了:

SELECT jdoc
FROM customers, jsonb_array_elements(jdoc->'products') as products
WHERE (products->>'price')::numeric > 150

问题是大型数据库的性能会受到很大影响。

我可以使用什么索引来加速此查询?

我尝试过的目标:

  • GIN个索引(jsonb_opsjsonb_path_ops)。它们似乎只适用于像@>这样的存在运算符。

  • CREATE INDEX ON persons(((jsonb_array_elements(jdoc->'products')->>'price')::numeric))。哪个给我发数据类型不匹配错误。

    • 请注意,CREATE INDEX ON persons(((jdoc->'age')::numeric))有效且允许我快速查询(jdoc->>'age')::numeric < 30

1 个答案:

答案 0 :(得分:2)

你可以创建一个函数并使用它:

CREATE FUNCTION max_price(jsonb) RETURNS double precision
   LANGUAGE sql IMMUTABLE AS
$$SELECT max(p.price)
FROM jsonb_to_recordset($1->'products')
        AS p(name text, price double precision)$$;

CREATE INDEX customers_ind ON customers(max_price(jdoc));

然后这个索引可以用于这样的查询:

EXPLAIN SELECT jdoc FROM customers WHERE max_price(jdoc) > 150;

                                   QUERY PLAN
--------------------------------------------------------------------------------
 Index Scan using customers_ind on customers  (cost=0.12..8.14 rows=1 width=36)
   Index Cond: (max_price(jdoc) > '150'::double precision)
(2 rows)

这不是您的查询,但它应该是等效的。