SQL Database / SQL Server 2025 では、JSON データ型 をサポートしており、JSON フォーマットのデータを格納するための専用のデータ型を使用することができます。
JSON データ型は「Latin1_General_100_BIN2_UTF8」の照合順序により UTF-8 のエンコードが使用されるという特徴の他に「圧縮用に最適化された、より効率的なストレージ」もメリットとして挙げられています。
通常の文字列データ型と比較して、JSON データ型がどの程度ストレージの格納効率が変化するのかが気になったので、SQL Database で確認してみました。
ストレージ格納効率の比較
今回は文字列データ型との格納効率を比較するため、同一のデータで次のデータ型で JSON フォーマットのデータを表現しています。
- nvarchar(max): UTF-16
- varchar(max): Shift JIS
- varchar(max): UTF-8
- json
JSON データ型のほうが格納効率が悪いケース
JSON フォーマットのデータの生成については、カラムの情報を使用した次のようなクエリで JSON AUTO を使用して生成を行い、DATALENGTH を使用してバイト数の取得を行います。
SELECT SUM(DATALENGTH(CAST(json_data AS nvarchar(max)))) AS nvarchar_max, SUM(DATALENGTH(CAST(json_data COLLATE Japanese_XJIS_140_CI_AS AS varchar(max)))) AS varchar_max, SUM(DATALENGTH(CAST(json_data COLLATE Japanese_XJIS_140_CI_AS_UTF8 AS varchar(max)))) AS varchar_max_utf8, SUM(DATALENGTH(CAST(json_data AS json))) AS json FROM ( SELECT TOP 1000 (SELECT * FROM sys.all_columns AS T2 WHERE T2.object_id = T1.object_id AND T2.column_id = T1.column_id FOR JSON AUTO,WITHOUT_ARRAY_WRAPPER) AS json_data FROM sys.all_columns AS T1 ORDER BY object_id DESC ) AS T GO
このクエリでは次のような JSON のデータが生成されています
{
"object_id": -1072372588,
"name": "GRANTOR",
"column_id": 1,
<省略>
"is_masked": false,
"is_data_deletion_filter_column": false,
"is_dropped_ledger_column": false
}
シンプルな 1 レコードの JSON が生成されるクエリとなっており、この JSON データの格納効率を確認しています。今回は Shift JIS と UTF-8 の格納効率の違いを出すようにしているため、テーブルに日本語列を作成して差が出るようにしています。
実際の取得結果が次のようになります。
今回のケースであれば、「varchar(max)」が使用されるデータサイズが一番小さくなっています。文字列データ型の格納効率の違いについては UTF-8 と UTF-16 でのストレージの相違点 に記載されていますが、Shift JIS で表現できる文字であれば Shift JIS の varchar(max) を使用するのが一番サイズが小さくなっています。
今回のデータであれば、「nvarchar(max) > json > varchar(max): UTF-8 > varchar(max): Shift JIS」という関係になっています。
JSON データ型の特徴として、冒頭に記載した「圧縮用に最適化された、より効率的なストレージ」がありますが、これは、単一レコードの JSON データ型では効果はなく、シンプルな JSON データの場合は JSON データ型ではなく、varchar(max) にデータを格納したほうが効率が良いケースがあるようです。
JSON データ型のほうが格納効率が良いケース
JSON データ型のほうが格納効率が良いケースですが次のようなクエリの場合は、JSON データ型のほうが格納効率が良くなります。
SELECT SUM(DATALENGTH(CAST(json_data AS nvarchar(max)))) AS nvarchar_max, SUM(DATALENGTH(CAST(json_data COLLATE Japanese_XJIS_140_CI_AS AS varchar(max)))) AS varchar_max, SUM(DATALENGTH(CAST(json_data COLLATE Japanese_XJIS_140_CI_AS_UTF8 AS varchar(max)))) AS varchar_max_utf8, SUM(DATALENGTH(CAST(json_data AS json))) AS json FROM ( SELECT TOP 1000 (SELECT TOP 5 * FROM sys.all_columns AS T2 WHERE T2.object_id = T1.object_id FOR JSON AUTO) AS json_data FROM sys.all_columns AS T1 ORDER BY object_id DESC ) AS T GO
このクエリでは、次のような JSON のデータが生成されています。
[
{
"object_id": -1072372588,
"name": "GRANTOR",
"column_id": 1,
<省略>
"is_masked": false,
"is_data_deletion_filter_column": false,
"is_dropped_ledger_column": false
},
{
"object_id": -1072372588,
"name": "GRANTEE",
"column_id": 2,
<省略>
"is_masked": false,
"is_data_deletion_filter_column": false,
"is_dropped_ledger_column": false
},
{
"object_id": -1072372588,
"name": "TABLE_CATALOG",
"column_id": 3,
<省略>
"is_masked": false,
"is_data_deletion_filter_column": false,
"is_dropped_ledger_column": false
},
{
"object_id": -1072372588,
"name": "TABLE_SCHEMA",
"column_id": 4,
<省略>
"is_masked": false,
"is_data_deletion_filter_column": false,
"is_dropped_ledger_column": false
},
{
"object_id": -1072372588,
"name": "TABLE_NAME",
"column_id": 5,
<省略>
"is_masked": false,
"is_data_deletion_filter_column": false,
"is_dropped_ledger_column": false
}
]
このような JSON データを格納した場合は、格納効率が異なってきます。
先ほどの結果は、「nvarchar(max) > json > varchar(max): UTF-8 > varchar(max): Shift JIS」となっていました。
今回のデータでは、「nvarchar(max) > varchar(max): UTF-8 > varchar(max): Shift JIS > json」となっており、JSON データ型が一番格納効率が高くなっています。
単一レコードの JSON データ型ではなく、類似のフォーマットをデータが複数レコード格納されている場合は、JSON データ型のほうが格納効率が良いという傾向があるようです。
JSON データ型をストレージの格納効率の最適化を目的として使用する場合、実際に格納されるデータを DATALENGTH でバイト数を確認し、圧縮による効果があるのかを確認すると良いのかもしれませんね。