クエリ
テーブル定義がありません。仮定:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
value
を見つけるには および指定されたoid
の行 および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'
これは暗黙のLATERAL
加入。比較:
- JSON型内の配列要素のクエリ
2)
oid
の3列のテーブルを取得する最速の方法は何ですか 、instance
およびvalue.
jsonb_populate_recordset()
を使用すると思います 、次に、テーブル定義でデータ型を指定できます。 text
を想定 すべての人のために:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
永続化された(非一時的な)テーブルである可能性もあります。これは現在のセッション専用です。次に:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
それで全部です。書き直された最初のクエリ:
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';
しかし、それは遅い 最初のクエリより。より大きなテーブルでのパフォーマンスの鍵は、インデックスのサポートです:
インデックス
正規化された(変換された)テーブルまたは質問で提案した代替レイアウトに簡単にインデックスを付けることができます。 現在のレイアウトのインデックス作成 それほど明白ではありませんが、可能性もあります。最高のパフォーマンスを得るには、data
のみの機能インデックスをお勧めします。 jsonb_path_ops
のキー 演算子クラス。ドキュメントごと:
jsonb_ops
の技術的な違い およびjsonb_path_ops
GINindexは、前者がデータ内の各キーと値に対して独立したインデックスアイテムを作成し、後者がデータ内の各値に対してのみインデックスアイテムを作成することです。
これは驚異的に機能するはずです パフォーマンスのために:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
次のように、JSON配列要素の完全一致のみが機能すると予想される場合があります。
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0", "value": "1234"}]';
JSON配列表記に注意してください( []
を囲んでいます )提供された値の、それは必須です。
ただし、キーのサブセットを持つ配列要素 同様に機能します:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
難しいのは、疑わしくないように見える追加の述語value <> '1'
を組み込むことです。 。すべての述語を同じに適用するように注意する必要があります 配列要素。これを最初のクエリと組み合わせることができます:
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á。
特別インデックス
テーブルが巨大な場合は、インデックスサイズが決定的な要因になる可能性があります。この特別なソリューションのパフォーマンスを機能インデックスと比較できます:
この関数は、 oid-instanceのPostgres配列を抽出します 特定のjsonb
からの組み合わせ 値:
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$
これに基づいて機能インデックスを作成できます:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
そして、それに基づいてクエリを実行します:
SELECT * FROM configuration
WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
キーなしで結合された値のみを格納するため、インデックスは大幅に小さくする必要があるという考え方です。 配列 封じ込め演算子@>
それ自体は、jsonb包含演算子 @>
と同様に機能する必要があります 。大きな違いはないと思いますが、どちらが速いのか非常に興味があります。
この関連する回答の最初の解決策と同様です(ただし、より専門的です):
- JSON配列内の要素を検索するためのインデックス
脇:
-
oid
は使用しません Postgresの内部目的でも使用されるため、列名として使用されます。 - 可能であれば、JSONを使用しない正規化されたプレーンなテーブルを使用します。