[解決済み] JSON配列の要素を検索するためのインデックス
質問
以下のようなテーブルがあります。
CREATE TABLE tracks (id SERIAL, artists JSON);
INSERT INTO tracks (id, artists)
VALUES (1, '[{"name": "blink-182"}]');
INSERT INTO tracks (id, artists)
VALUES (2, '[{"name": "The Dirty Heads"}, {"name": "Louis Richards"}]');
この質問には関係ありませんが、他にもいくつかのカラムがあります。それらをJSONとして保存する理由があるのです。
私がやろうとしていることは、特定の アーティスト名 を持つトラックを検索することです (完全一致)。
このクエリで
SELECT * FROM tracks
WHERE 'ARTIST NAME' IN
(SELECT value->>'name' FROM json_array_elements(artists))
例えば
SELECT * FROM tracks
WHERE 'The Dirty Heads' IN
(SELECT value->>'name' FROM json_array_elements(artists))
しかし、これはフルテーブルスキャンを行うので、あまり高速ではありません。関数を使ってGINインデックスを作成してみました。
names_as_array(artists)
を使用し、そして
'ARTIST NAME' = ANY names_as_array(artists)
を使用した場合は、インデックスが使用されず、クエリの実行速度が大幅に低下します。
どのように解決するのですか?
jsonb
Postgres 9.4+で
バイナリJSONデータ型
jsonb
は、インデックスのオプションを大きく改善しました。GIN インデックスを
jsonb
配列に直接 GIN インデックスを持てるようになりました。
CREATE TABLE tracks (id serial, artists jsonb); -- !
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
配列を変換する関数は必要ありません。これならクエリに対応できる。
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@>
である。
jsonb
"contains"演算子です。
で、GINインデックスを使用することができます。(ただし
json
だけです。
jsonb
!)
または
を使う場合は、より特殊でデフォルトではない GIN 演算子クラスである
jsonb_path_ops
をインデックスとして使用します。
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (artists jsonb_path_ops); -- !
同じクエリで
現在
jsonb_path_ops
のみをサポートしています。
@>
演算子のみをサポートします。しかし、一般的にはるかに小さく、高速です。インデックスのオプションはもっとあります。
マニュアルに詳細があります。
.
もし
列
artists
がこの例で表示されているような名前だけを保持するのであれば、単に
値
をJSONテキストとして保存する方が効率的です。
プリミティブ
と、冗長な
キー
はカラム名とすることができます。
JSONオブジェクトとプリミティブ型の違いに注意してください。
CREATE TABLE tracks (id serial, artistnames jsonb);
INSERT INTO tracks VALUES (2, '["The Dirty Heads", "Louis Richards"]');
CREATE INDEX tracks_artistnames_gin_idx ON tracks USING gin (artistnames);
クエリを実行します。
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
?
はオブジェクトに対して動作しません
の値です。
は、単に
キー
と
配列要素
.
または
CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING gin (artistnames jsonb_path_ops);
クエリ
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
名前の重複が多い場合、より効率的です。
json
Postgres 9.3+では
これは
IMMUTABLE
機能
:
CREATE OR REPLACE FUNCTION json2arr(_j json, _key text)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT elem->>_key FROM json_array_elements(_j) elem)';
これを作成する 機能的 インデックス :
CREATE INDEX tracks_artists_gin_idx ON tracks
USING gin (json2arr(artists, 'name'));
そして
クエリ
のようにします。の中の式は
WHERE
句の式はインデックスの式と一致しなければなりません。
SELECT * FROM tracks
WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
コメントでのフィードバックを受けて更新しました。私たちは
配列演算子
を使用して、GINインデックスをサポートします。
は
"is contained by" 演算子
<@
をこの場合
機能揮発に関する注意点
関数を宣言する際に
IMMUTABLE
であっても
json_array_elements()
はなく
はなかったことに。
最も
JSON
関数は、以前は
STABLE
でなく
IMMUTABLE
.
を変更するようにハッカーリストで議論されていました。
ほとんどは
IMMUTABLE
になっています。で確認してください。
SELECT p.proname, p.provolatile
FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname = 'pg_catalog'
AND p.proname ~~* '%json%';
ファンクショナルインデックスでは
IMMUTABLE
関数でのみ動作します。
関連
-
[解決済み] 正しいJSONコンテンツタイプは何ですか?
-
[解決済み] JSONでコメントを使用することはできますか?
-
[解決済み] なぜGoogleはJSONレスポンスにwhile(1);を前置するのでしょうか?
-
[解決済み] リスト内のアイテムのインデックスを検索する
-
[解決済み] cURLでJSONデータをPOSTするにはどうすればよいですか?
-
[解決済み] JavaScriptでJSONをきれいに印刷する
-
[解決済み] リストの最後の要素を取得する方法
-
[解決済み] SQLテーブルで重複する値を検索する
-
[解決済み] インデックスを指定してリストから要素を削除する方法
-
[解決済み] SQL Serverでストアドプロシージャ内のテキストを検索する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] SQLのカラム名があいまいな場合のクエリエラー
-
[解決済み] SQL Server の DateTime データ型から日付だけを返す方法
-
[解決済み] 複数の列でgroup byを使用する
-
[解決済み] mysqldumpで特定のテーブルをスキップする
-
[解決済み] SQLiteデータベースで、一度に複数行を挿入することは可能ですか?
-
[解決済み] DISTINCTでCOUNT(*)を選択する
-
[解決済み】Postgresの配列に値が存在するかどうかを確認する
-
[解決済み】新しいPostgreSQL JSONデータ型内のフィールドを使用してクエリを実行するにはどうすればよいですか?
-
[解決済み] PostgreSQLは配列のカラムにインデックスを付けることができますか?
-
[解決済み] JSON型内の配列要素を問い合わせる