2014年8月6日水曜日

PostgreSQL 9.4で強化されたJSON型

今回はPostgreSQL 9.4で強化されたJSON型について2週に分けてご紹介します。

PsotgreSQL9.4で更に強化されるJSON型

これまでにもJSON型については何度か解説してきました。現在のJSON型も非常に強力ですが、PostgreSQL9.4ではJSON型が更に強化されます。どのように強化されたのか解説します。

■ 現在のJSON型と新しいJSONB型

現在のJSON型はテキストデータとして保存されています。JSON型に保存されたデータにアクセスするには、テキストとして保存されたJSONデータをアンシリアライズしてからアクセスする必要がありました。新しいJSONB型はJSONデータをPostgreSQLネイティブのデータ型として保存します。PostgreSQLネイティブのデータ型として保存されるため、JSONデータのテキストをアンシリアライズせずにアクセスできるようになります。つまりより効率的に保存・アクセスできるようになります。

JSON型とJSONB型はほぼ同じ動作を行います。特別な理由が無い場合はJSON型よりJSONB型を利用する事が推奨されます。動作が最も異なる部分は重複キーが存在する場合です。JSON型では重複キーもテキストとして保存されますがJSONB型では最後に定義された値が有効になり、重複キーは保存されません。JSONBとJSONの動作の違いをまとめると以下のようになります。

  • 重複キーは保存されなくなり、最後の値が保存される(関数などでJSON型にアクセスした場合も結果的には同じ)
  • スペース文字が保存されなくなる
  • キーの順序が保存されなくなる
  • JSONデータに要素が含まれるか確認可能になる

多くのアプリケーションではキーの順序が変わる事に問題はないと思われますが、単純にJSONデータ型の中身を順番に出力しているアプリケーションでは注意が必要です。

■■ 新しいJSONB型のJSONデータ型とPostgreSQLデータ型のマッピング

RFC-7159/JSONデータ型   PostgreSQLデータ型
  string                text >
  number                numeric
  boolean               boolean
  null                  unknown

■ 基本的な動作

JSONB型とJSON型で大きな違いはありません。

基本的な動作

  username@127 ~=# SELECT '5'::jsonb;
  jsonb
  -------
  5
  (1 行)
  時間: 1.044 ms
  username@127 ~=# SELECT '5'::json;
  json
  ------
  5
  (1 行)
  時間: 0.356 ms
  username@127 ~=# SELECT '[1, 2, "foo", null]'::jsonb;
  jsonb
  ---------------------
  [1, 2, "foo", null]
  (1 行)
  時間: 0.223 ms
  username@127 ~=# SELECT '[1, 2, "foo", null]'::json;
  json
  ---------------------
  [1, 2, "foo", null]
  (1 行)
  時間: 0.193 ms
  username@127 ~=# SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb;
    jsonb
  --------------------------------------------------
  {"bar": "baz", "active": false, "balance": 7.77}
  (1 行)
  時間: 0.242 ms
  username@127 ~=# SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json;
  json
  -------------------------------------------------
  {"bar": "baz", "balance": 7.77, "active":false}
  (1 行)
  時間: 0.194 ms

最後の例ではキーの順序が保持されていない事が分かります。この他にも、同じキーを保つ場合、最後の要素が優先されます。

重複キーを保つデータ

  username@127 ~=# SELECT '{"bar": "baz", "bar": "foo", "balance": 7.77, "active":false}'::jsonb;
  jsonb
  --------------------------------------------------
  {"bar": "foo", "active": false, "balance": 7.77}
  (1 行)
  時間: 0.255 ms
  username@127 ~=# SELECT '{"bar": "baz", "bar": "foo", "balance": 7.77, "active":false}'::json;
  json
  ---------------------------------------------------------------
  {"bar": "baz", "bar": "foo", "balance": 7.77, "active":false}
  (1 行)
  時間: 0.241 ms

JSONB型では空白は無視されます。

空白付きのデータ

  username@127 ~=# SELECT '     5'::jsonb;
  jsonb
  -------
  5
  (1 行)
  時間: 0.197 ms
  usernme@127 ~=# SELECT '     5'::json;
  json
  --------
  5
  (1 行)
  時間: 0.196 ms

■ "@>" オペレータ

JSONB型は"@>"オペレータで要素が含まれるか確認できます。この機能はJSON型にはありません。

"@>"オペレータの利用例

  username@127 ~=# SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb":true}'::jsonb @> '{"version":9.4}'::jsonb;
  ?column?
  ----------
  t
  (1 行)
  時間: 0.678 ms

JSONデータを操作する場合、特定の要素が含まれるか確認したい場合は多くあります。"@>"オペレータは便利なオペレータです。配列のチェックよりオブジェクトのチェックに向いています。

■ GINインデックス

JSONB型はGIN(汎用転置インデックス)をサポートしています。 "@>", "?", "?&"および"?|"オペレータをサポートしています。 このため、関数インデックスを利用しなくてもJSONデータを高速に検索可能です。

GINインデックスの使い方

  CREATE INDEX index_name ON table_has_jsonb USING GIN (jsonb_column);

オプションを指定しない場合、デフォルトのopclassが利用されます。opclass以外にjsonb_hash_opsもサポートされています。

GINインデックスの使い方

  CREATE INDEX index_name ON table_has_jsonb USING GIN (jsonb_column jsonb_hash_ops);

jsonb_hash_opsを指定すると"@>"オペレータのみが利用できます。Webアプリなどでtag検索を実装する場合に非常に便利です。(レストランなどを検索する場合に、目的、ジャンル、設備、サービスなどタグとして保存し、適合するレコードを抽出する検索を高速に行えます)

次回に続く。

0 件のコメント:

コメントを投稿