sql >> データベース >  >> RDS >> PostgreSQL

テーブルとしてのPostgres9.4jsonb配列

    クエリ

    テーブル定義がありません。仮定:

    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を使用しない正規化されたプレーンなテーブルを使用します。



    1. ハロウィーンの問題–パート1

    2. JOINとLEFTJOINおよびWHERE条件のパフォーマンスの提案をより詳細に説明する

    3. MySQLINステートメントのPDOバインディング値

    4. .NET MySqlCommandでMySqlユーザー定義変数を使用するにはどうすればよいですか?