Truy vấn
Định nghĩa bảng của bạn bị thiếu. Giả sử:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
Để tìm giá trị value
và hàng của nó cho oid
đã cho và instance
:
SELECT c.config_id, d->>'value' AS value
FROM configuration c
, jsonb_array_elements(config->'data') d -- default col name is "value"
WHERE d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3'
AND d->>'instance' = '0'
AND d->>'value' <> '1'
Đó là một LATERAL
ngầm hiểu tham gia. So sánh:
- Truy vấn các phần tử mảng bên trong kiểu JSON
2) Cách nhanh nhất để lấy bảng có 3 cột
oid
là gì ,instance
và giá trịvalue.
Tôi cho rằng sử dụng jsonb_populate_recordset()
, thì bạn có thể cung cấp các kiểu dữ liệu trong định nghĩa bảng. Giả sử text
cho tất cả:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
Cũng có thể là một bảng lâu dài (không tạm thời). Cái này chỉ dành cho phiên hiện tại. Sau đó:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
Đó là tất cả. Truy vấn đầu tiên được viết lại:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
WHERE d.oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3'
AND d.instance = '0'
AND d.value <> '1';
Nhưng điều đó chậm hơn so với truy vấn đầu tiên. Chìa khóa để đạt được hiệu suất với bảng lớn hơn là hỗ trợ chỉ mục:
Chỉ mục
Bạn có thể dễ dàng lập chỉ mục bảng chuẩn hóa (đã dịch) hoặc bố cục thay thế mà bạn đã đề xuất trong câu hỏi. Lập chỉ mục bố cục hiện tại của bạn là không rõ ràng, nhưng cũng có thể. Để có hiệu suất tốt nhất, tôi đề xuất một chỉ mục chức năng chỉ trên data
khóa bằng jsonb_path_ops
lớp toán tử. Theo tài liệu:
Sự khác biệt về kỹ thuật giữa
jsonb_ops
và mộtjsonb_path_ops
GINindex là cái trước tạo các mục chỉ mục độc lập cho mỗi khóa và giá trị trong dữ liệu, trong khi cái sau tạo các mục chỉ mục chỉ hiển thị giá trị trong dữ liệu.
Điều này sẽ làm nên điều kỳ diệu cho hiệu suất:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
Người ta có thể mong đợi rằng chỉ có một kết hợp hoàn chỉnh cho một phần tử mảng JSON mới hoạt động, như:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0", "value": "1234"}]';
Lưu ý ký hiệu mảng JSON (với bao gồm []
) của giá trị đã cung cấp, đó là giá trị bắt buộc.
Nhưng các phần tử mảng có tập hợp khóa con hoạt động tốt:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
Phần khó là kết hợp vị từ được thêm vào có vẻ không tốt của bạn value <> '1'
. Cần phải cẩn thận để áp dụng tất cả các vị từ cho cùng một phần tử mảng. Bạn có thể kết hợp điều này với truy vấn đầu tiên:
SELECT c.*, d->>'value' AS value
FROM configuration c
, jsonb_array_elements(config->'data') d
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3", "instance": "0"}]'
AND d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3' -- must be repeated
AND d->>'instance' = '0' -- must be repeated
AND d->>'value' <> '1' -- here we can rule out
Voilá.
Chỉ mục đặc biệt
Nếu bảng của bạn lớn, kích thước chỉ mục có thể là một yếu tố quyết định. Bạn có thể so sánh hiệu suất của giải pháp đặc biệt này với một chỉ số chức năng:
Hàm này trích xuất một mảng Postgres của oid-instance kết hợp từ một jsonb
nhất định giá trị:
CREATE OR REPLACE FUNCTION f_config_json2arr(_j jsonb)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
$func$
SELECT ARRAY(
SELECT (elem->>'oid') || '-' || (elem->>'instance')
FROM jsonb_array_elements(_j) elem
)
$func$
Chúng tôi có thể xây dựng một chỉ mục chức năng dựa trên điều này:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
Và dựa trên truy vấn:
SELECT * FROM configuration
WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
Ý tưởng là chỉ mục nên nhỏ hơn đáng kể vì nó chỉ lưu trữ các giá trị kết hợp mà không có khóa. Mảng toán tử ngăn chặn @>
chính nó sẽ hoạt động tương tự như toán tử chứa jsonb @>
. Tôi không mong đợi một sự khác biệt lớn, nhưng tôi sẽ rất quan tâm đến việc nào là nhanh hơn.
Tương tự như giải pháp đầu tiên trong câu trả lời liên quan này (nhưng chuyên biệt hơn):
- Chỉ mục để tìm một phần tử trong mảng JSON
Bên cạnh:
- Tôi sẽ không sử dụng
oid
làm tên cột vì nó cũng được sử dụng cho các mục đích nội bộ trong Postgres. - Nếu có thể, tôi sẽ sử dụng một bảng đơn giản, chuẩn hóa không có JSON.