3 JSONデータの格納および管理の概要

この概要では、(1) JSON列のデータ型、(2) JSONデータ向けのLOB記憶域の考慮事項、(3) JSON列に整形式のJSONデータが格納されていることの確認、について説明します。

JSON列のデータ型

Oracle DatabaseにJSONデータを格納するには、データ型がJSONVARCHAR2CLOBまたはBLOBの列を使用します。どのデータ型を使用しても、それらのデータ型の他のデータを操作する場合と同様に、JSONデータを操作できます。標準のデータ型を使用してJSONデータを格納すると、アドバンスト・レプリケーションなどのOracle Databaseのすべての機能で、JSON文書が格納された表を使用できるようになります。

ネイティブなバイナリ形式でJSONデータを格納するJSONデータ型を使用することをお薦めします。

他のいずれかの型を使用する場合、どれを使用するかは、一般的に、管理が必要なJSON文書のサイズによって決まります。

  • 最も大きいJSON文書が4000バイト(または文字)を超えないことが確かな場合は、VARCHAR2(4000)を使用します脚注1脚注1

    Oracle Exadataを使用している場合は、VARCHAR2(4000)を選択すると、パフォーマンスの向上のために一部のJSON操作の実行をExadataの記憶域セルに押し下げることができるため、パフォーマンスを向上させることができます。

  • JSON文書のうち、いくつかが4000バイト(または文字)を超えるということがわかっており、すべて32767バイト(または文字)以下であることが確かな場合は、VARCHAR2(32767)を使用します脚注1

    VARCHAR2(32767)の場合、文書の最初の約3.5Kバイト(または文字)は、表の行の一部として表内に格納されます。これは、VARCHAR2(4000)ではなくVARCHAR2(32767)を使用することで増えるコストが、約3.5Kより大きい文書にのみ適用されることを意味します。ほとんどの文書がこのサイズよりも小さい場合は、VARCHAR2(4000)を使用する場合と比べてパフォーマンスにほとんど差は出ません。

    Oracle Exadataを使用する場合は、行内に格納されているすべての文書に対してプッシュダウンが有効になります。

  • 32767バイト(または文字)よりも大きいJSON文書があることがわかっている場合は、BLOB (バイナリ・ラージ・オブジェクト)またはCLOB (キャラクタ・ラージ・オブジェクト)の記憶域を使用します脚注1

JSON列に整形式のJSONデータが格納されていることの確認

JSONデータ型を使用してJSONデータを格納する場合(推奨)、データは整形式のJSONデータであることが保証されます。それ以外の場合は格納できません。

JSONデータ型を使用してJSONデータを格納しない場合は、SQL/JSON条件is jsonを使用して、一部のJSONデータが整形式かどうかを確認できます。この場合、整形式のJSONデータ以外のデータが一部の行に含まれることが予期される場合を除いて、すべてのJSON列にis jsonチェック制約を適用することをお薦めします。

JSON解析のオーバーヘッドは、条件が挿入や更新のパフォーマンスに重大な影響を及ぼさないことを評価するといったもので、制約を除外すると、JSONデータの問合せに単純なドット表記法の構文を使用できないことになります。

何をもって整形式のJSONデータとするかは明確ではありません。実際には、JSONデータには、標準の定義に厳密には従わない特徴がいくつかあることが一般的です。JSONデータの特定の列に、標準の定義(厳密な構文)と、一般的に使用されるJavaScriptのような構文(緩慢な構文)のどちらの構文を必要とするかを制御できます。Oracle Database向けのデフォルトのSQL/JSON構文は緩慢です。どの種類の構文を使用するかは、条件is jsonで制御します。JSON列にis jsonチェック制約を適用することで、このように緩慢なJSON構文をデフォルトで使用できるようになります。

JSONデータにLOB記憶域を使用する際の考慮事項

JSONデータにLOB記憶域を使用する場合は、CLOB記憶域ではなくBLOBを使用することをお薦めします。

これは、データベースのキャラクタ・セットがOracleの推奨値であるAL32UTF8に設定されている場合に、特に該当します。AL32UTF8のデータベースでは、CLOBインスタンスはUCS2キャラクタ・セットを使用して格納されます。これは、1文字に2バイト必要になることを意味します。ある文書の内容の大半が、キャラクタ・セットAL32UTF8でシングルバイトを使用して表される文字で構成されている場合は、この文書に必要な記憶域が2倍になります。

データベースのキャラクタ・セットがAL32UTF8ではない場合でも、CLOBではなくBLOBの記憶域を選択すると、JSON文書を格納するときにキャラクタ・セットの変換が必要なくなるという利点があります(JSONデータのキャラクタ・セットおよび文字エンコーディングを参照)。

ラージ・オブジェクト(LOB)を使用する場合は、次のようにすることをお薦めします。

  • LOB (COLUMN_NAME) STORE AS (CACHE)CREATE TABLE文で使用して、JSON文書の読取り操作が、データベース・バッファ・キャッシュを使用して最適化されるようにします。

  • SecureFiles LOBを使用します。JSONデータに必要な記憶域を減らすために、Oracle Advanced Compressionの使用も検討します。圧縮を使用する場合は、Mediumの圧縮オプションをお薦めします。このオプションは、容量の節約とパフォーマンスの適度なバランスを提供します。

SQL/JSONファンクションおよび条件では、データが格納されるのがBLOBCLOBかという特別な考慮事項なしに、JSONデータを使用できます。アプリケーション開発の観点から見ると、BLOBコンテンツと連携するためのAPIコールは、CLOBコンテンツと連携するためのものとほとんど同じです。

CLOBではなくBLOB記憶域を選択する(JSONまたはその他の種類のデータを対象に)マイナス面は、SQL*Plusなどのコマンドライン・ツールを使用したBLOBコンテンツとの連携がより難しい場合があるということです。次に例を示します。

  • BLOB列からデータを選択するときに、出力可能なテキストとしてそのデータを表示する場合に、SQLファンクションto_clobを使用する必要がある。

  • BLOB列を対象に挿入または更新の操作を実行するときに、SQLファンクションrawtohexを使用して、文字列を明示的にBLOB形式に変換する必要がある。Foot 2

関連項目:

クライアントを使用してJSONデータをLOBインスタンスとして取得する場合の考慮事項

Oracle Call Interface (OCI)やJava Database Connectivity (JDBC)などのクライアントで、LOBロケータ・インタフェースを使用してLOBバッチでデータベースからJSONデータを取得する場合は、次の最適化を検討してください。

  • LOBプリフェッチ・サイズを大きい値(65 KBなど)に設定します。

  • フェッチされたLOBを、各行の読取り後に解放します。そうしないと、パフォーマンスが低下し、メモリーがリークする可能性があります。

    (ただし、JSON型オペランドでの操作からのLOBロケータを使用する場合については、次を参照)。

LOBデータ・インタフェースを使用する場合:

  • OCIでは、BLOBデータおよびCLOBデータに対してデータ型SQLT_BINおよびSQLT_CHRをそれぞれ使用します。

  • JDBCでは、BLOBデータおよびCLOBデータに対してメソッドgetBytes()およびgetString()をそれぞれ使用します。

JSON型オペランドでのSQL/JSON操作によって戻されたLOBロケータがあるLOBロケータ・インタフェースを使用する場合:

  • LOBは一時的であり読取り専用です。

  • LOBを明示的に解放する必要はありません。次のフェッチで自動的に解放されます。

この例は、JDBCでLOBロケータ・インタフェースを使用する方法を示しています。


Statement stmt = conn.createStatement(); // conn is a java.sql.Connection
stmt.setFetchSize(1000); // Set batch fetch size to 1000 rows
// set LOB prefetch size to be 65 KB
((OraclePreparedStatement)stmt).setLobPrefetchSize(65000);
// Query the JSON data in column jdoc of table myTab, returning JSON data as a BLOB instance
rset = stmt.executeQuery(
         "SELECT id, json_serialize(jdoc RETURNING BLOB) FROM myTab");
while (rset.next()) { // Iterate over the returned rows
  Blob blob = rset.getBlob (2);
  // Do something with the BLOB instance for the row...

  // Free the LOB at the end of the iteration.
  // Not needed if the LOB is returned by an operation on a
  // JSON-type operand, that is, if jdoc is a JSON-type column.
  blob.free();
}
rset.close();


脚注の凡例

脚注1: 制限がバイト単位かそれとも文字単位かは、セッション・パラメータNLS_LENGTH_SEMANTICSによって決まります。
脚注2: SQLファンクションrawtohexの戻り値は32767バイトに制限されています。値は、この長さを超えて変換されたデータをすべて削除するように切り捨てられます。