メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
MySQL のネイティブな JSON 列型は、挿入時に JSON を検証し、効率的にアクセスできるようバイナリ形式で格納し、ドキュメント全体を解析せずに個々のフィールドを読み書きするための一連の関数を提供します。

JSON の格納

MySQL は挿入時に JSON を検証します。不正な形式の JSON を挿入するとエラーになります。

JSON フィールドの読み取り

JSON_EXTRACT(column, path) または短縮形の -> を使います。
どちらも JSON 値を返します。つまり、引用符付きの文字列 "Acme" です。引用符のないプレーンな文字列を得るには、->>(JSON_UNQUOTE(JSON_EXTRACT(...)) の短縮形)を使います。
パス構文:
  • $.key — オブジェクトのフィールドにアクセスします
  • $.array[0] — インデックスで配列要素にアクセスします
  • $.array[*] — 配列のすべての要素
  • $.** — 再帰ワイルドカード(任意の深さのすべての値)

JSON フィールドでのフィルタリング

->> は文字列を返すため、明示的にキャストしない限り、(16 ではなく)'16' と比較するのが正しい書き方です。キャストする場合は CAST(attributes ->> '$.ram_gb' AS UNSIGNED) とします。

JSON の変更

主な関数:

JSON フィールドのインデックス化

JSON 列そのものに直接インデックスを作成することはできません。特定の JSON フィールドにインデックスを作成するには、生成列を作り、その列にインデックスを作成します。
これで WHERE attributes ->> '$.brand' = 'Acme' は idx_brand を使えます。MySQL は、生成列の式がクエリ条件と一致することを認識します。 この点はMySQL のデータ型の選択でより詳しく説明しています。インデックスが必要になるほど頻繁に JSON フィールドをクエリする場合には、これが推奨されるパターンです。

JSON と正規化された列の比較

構造が本当に可変である場合(ユーザーが設定できる属性、イベントのメタデータ、サードパーティ API のペイロード)には JSON を使います。構造が固定されていて、フィールドに対してフィルタリング、結合、または集計を行う必要がある場合は、正規化された列を使います。

よくある質問

包含クエリのために JSON 配列にインデックスを作成できますか?

標準のインデックスでは直接作成できません。JSON_CONTAINS クエリでは、配列を別の子テーブルに抽出する(正規化する)か、配列を平坦化した生成列に全文インデックスを使わない限り、唯一の選択肢はフルテーブルスキャンです。高スループットの包含クエリには、正規化のほうが良い道です。

-> と ->> の違いは何ですか?

-> は JSON 値を返します(文字列は前後の引用符を含みます)。->> は引用符を外した文字列を返します。表示、連結、およびテキストを利用するあらゆる用途には、->> が適しています。ただし、等価比較は -> でも動作します。MySQL はもう一方のオペランドを先に JSON に変換するため、attributes -> '$.brand' = 'Acme' は一致します。

JSON を格納するとパフォーマンスが低下しますか?

大きな JSON ドキュメントから 1 つのフィールドを読み取るには、バイナリ構造の解析が必要です。これはテキストの解析より速いものの、ネイティブな列の読み取りより遅くなります。頻繁にアクセスするフィールドについては、生成列とインデックスのパターンによって、読み取りのパフォーマンスがネイティブな列と同等になります。

トラブルシューティング

関連項目