2016-12-15 91 views
2

我有一個9.4 Postgres數據庫,其中有一個包含jsonb字段的表。使用Postgres在json數組內部索引對象元素

的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
+0

使用關係數據模型而不是JSON。 – Abelisto

回答

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) 

這不是你的查詢,但它應該是等同的。

+0

但是這意味着如果我想查詢一個小於一個值的價格,我還必須創建第二個使用'min(p.price)'的函數/索引。我對嗎? – Kabbalah

+0

是的。這隻針對你問題中的特例。答案應該讓你知道如何解決像你這樣的問題。 –

+0

謝謝。在接受之前,我會等待一兩天,看看是否有其他選擇。 – Kabbalah