Postgres 9.4を使用して、列内の特定のキーを検索するときに使用されるjson列にインデックスを作成します。
たとえば、json列「animals」を持つ「farm」テーブルがあります。
Animals列には、一般形式のjsonオブジェクトがあります。
'{"cow": 2, "chicken": 11, "horse": 3}'
私はいくつかのインデックスを試しました(別々に):
(1) create INDEX animal_index ON farm ((animal ->> 'cow'));
(2) create INDEX animal_index ON farm using gin ((animal ->> 'cow'));
(3) create INDEX animal_index ON farm using Gist ((animal ->> 'cow'));
次のようなクエリを実行したい:
SELECT * FROM farm WHERE (animal ->> 'cow') > 3;
そのクエリにインデックスを使用させます。
このクエリを実行すると:
SELECT * FROM farm WHERE (animal ->> 'cow') is null;
(1)インデックスは機能しますが、不平等のために機能するインデックスを取得できません。
そのようなインデックスは可能ですか?
ファームテーブルには〜5000ファームしか含まれていませんが、そのうちのいくつかには100匹の動物が含まれており、クエリは私のユースケースには時間がかかりすぎます。このようなインデックスは、このクエリを高速化するために考えられる唯一の方法ですが、おそらく別のオプションがあります。
他の2つのインデックスは、単に ->>
operator はtext
を返しますが、明らかにjsonb
gin演算子クラスを念頭に置いています。 json
のみに言及していることに注意してください。ただし、実際には jsonb
が必要です。機能。
最適なインデックス戦略を作成するには、対象とするクエリをより厳密に定義する必要があります。牛だけに興味がありますか?またはすべての動物/すべてのタグ?どの演算子が可能ですか? JSONドキュメントには動物以外のキーも含まれていますか?それらをどうしますか? JSON文書に牛(またはその他)がまったく表示されない行をインデックスに含めますか?
仮定:
integer
です。すでに持っているのと同じように、機能的なbtreeインデックスをお勧めしますが、値を整数にキャストします。比較をtext
(ここで '2'は '1111'より大きい)として評価したいとは思わないでしょう。
CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)); -- !
インデックスの式の構文を明確にするために、キャストの省略形に追加の括弧のセットが必要です。
クエリで同じ式を使用して、インデックスが適用可能であることをPostgresに認識させます。
SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3;
より一般的なjsonb
インデックスが必要な場合は、以下を検討してください。
既知の静的な、ささいな動物の数(あなたがコメントしたような)については、次のような部分インデックスをお勧めします:
CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int))
WHERE (animal ->> 'cow') IS NOT NULL;
CREATE INDEX animal_index ON farm (((animal ->> 'chicken')::int))
WHERE (animal ->> 'chicken') IS NOT NULL;
等。
クエリにインデックス条件を追加する必要がある場合があります。
SELECT * FROM farm
WHERE (animal ->> 'cow')::int > 3
AND (animal ->> 'cow') IS NOT NULL;
冗長に見えるかもしれませんが、必要かもしれません。 ANALYZE
でテストします!