web-dev-qa-db-ja.com

JSONのPostgreSQLインデックス

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匹の動物が含まれており、クエリは私のユースケースには時間がかかりすぎます。このようなインデックスは、このクエリを高速化するために考えられる唯一の方法ですが、おそらく別のオプションがあります。

27
lnhubbell

他の2つのインデックスは、単に ->> operatortextを返しますが、明らかに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でテストします!

57