Postgresql
使用更大的運算符在 jsonb 數組中搜尋嵌套值
這是表定義(簡化):
CREATE TABLE documents ( document_id int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY, data_block jsonb NULL );
樣本值:
INSERT INTO documents (document_id, data_block) VALUES (878979, '{"COMMONS": {"DATE": {"value": "2017-03-11"}}, "PAYABLE_INVOICE_LINES": [ {"AMOUNT": {"value": 52408.53}}, {"AMOUNT": {"value": 654.23}} ]}') , (977656, '{"COMMONS": {"DATE": {"value": "2018-03-11"}}, "PAYABLE_INVOICE_LINES": [ {"AMOUNT": {"value": 555.10}} ]}');
我想搜尋其中一個
'PAYABLE_INVOICE_LINES'
元素包含'value'
大於 1000.00 的所有文件。我的查詢是
select * from documents d cross join lateral jsonb_array_elements(d.data_block -> 'PAYABLE_INVOICE_LINES') as pil where (pil->'AMOUNT'->>'value')::decimal > 1000
但是,由於我想限制為 50 個文件,所以我必須對結果進行分組
document_id
並將結果限制為 50。對於數百萬個文件,此查詢非常昂貴 - 10 秒有 100 萬個。
我嘗試在 jsonb 對象的數組上添加 GIN 索引。但它似乎只在使用 jsonb 運算符(如
@>
.你有一些想法來獲得更好的性能嗎?
這通常很難優化:
jsonb
這種測試沒有直接的運算符或索引支持。
EXISTS
至少應該比您擁有的更快,同時還避免重複行(多個數組元素匹配)和pil
結果中的附加(冗餘)列:SELECT * FROM documents d WHERE EXISTS ( SELECT FROM jsonb_array_elements(d.data_block -> 'PAYABLE_INVOICE_LINES') pil WHERE (pil->'AMOUNT'->>'value')::decimal > 1000 );
有關的:
為了使這個速度更快幾個數量級,提取每行的最大值並冗餘保存,或者
IMMUTABLE
在一個非常小且快速(但也是專門的)表達式索引中使用函式:CREATE OR REPLACE FUNCTION f_doc_max_amout(jsonb) RETURNS numeric AS $func$ SELECT max((a->'AMOUNT'->>'value')::numeric) FROM jsonb_array_elements($1) a $func$ LANGUAGE sql IMMUTABLE; CREATE INDEX documents_max_amount_idx ON documents (f_doc_max_amout(data_block -> 'PAYABLE_INVOICE_LINES'));
查詢(必須匹配索引表達式):
SELECT * FROM documents d WHERE f_doc_max_amout(data_block -> 'PAYABLE_INVOICE_LINES') > 1000;
dbfiddle在這裡