😊

DatabricksにおけるJSONデータ格納形式のパフォーマンス比較:VARIANT型 vs STRING型

に公開

1. 要約

Databricksプラットフォーム上でJSONデータを保存・処理する際の最適な形式を検証したものです。従来のSTRING型と、新しく導入されたVARIANT型について、同じ条件でクエリの実行速度を比較した結果、VARIANT型がSTRING型よりもはるかに高速であることが確認されました。

結論として、「DatabricksでJSONデータを扱う場合は、STRING型の使用をやめ、VARIANT型に移行すべき」 です。VARIANT型への移行は、クエリの高速化、コンピューティングリソースの削減、ストレージコストの最適化に直接的につながる、合理的で不可欠なステップです。

2. VARIANT型が高速で効率的な理由

この大きなパフォーマンスの差は、両データ型の根本的な仕組みの違いによるものです。

2.1. STRING型:毎回すべてを解析する非効率なアプローチ

STRING型はJSONデータを単なる「長い文字列」として保存します。これは、分厚いマニュアルを毎回最初のページから読み直して必要な情報を探すような作業を、クエリのたびに行うことに相当します。

  • 毎回発生する高コストな解析処理: クエリが実行されるたびに、get_json_objectなどの関数が各行のJSON文字列をすべて解析(パース) する必要があります。これによりCPUに非常に高い負荷がかかります。
  • 統計情報の欠如: データベースはSTRING型の「中身」を認識しないため、統計情報に基づく最適化(不要なデータの読み飛ばしなど)ができません。

2.2. VARIANT型:事前準備による効率的なアプローチ

一方、VARIANT型はJSONデータを単なる文字列として保存しません。これは索引(インデックス)を使って必要なページをすぐに開くような、効率的なアプローチです。

  • 解析処理の事前実行: データを書き込む時点でJSONを一度だけ解析し、最適化された内部形式(バイナリ形式) で保存します。クエリ時はこの構造化されたデータに直接アクセスするため、文字列解析の負荷が完全になくなります。
  • 統計情報を利用したデータ読み飛ばし: VARIANT型は、ネストされた値に関する統計情報を自動的に収集・管理します。これにより、クエリ実行時に無関係なデータファイルをまとめて読み飛ばす(プルーニング) ことができ、大規模なデータ処理においてI/O負荷を大幅に削減します。

3. 検証手順:パフォーマンス比較の方法

以下のSQLクエリを実行することで、両データ型のパフォーマンス差を具体的に計測・比較できます。

【前提条件】

  • Databricks SQL Warehouseを使用。

3.1. ステップ1: テストデータとテーブルの準備

-- テスト用の元データを作成
CREATE OR REPLACE TEMPORARY VIEW raw_json_data AS
SELECT 1 AS id, '{"user": {"id": 1, "name": "Taro", "age": 32}, "items": ["pc", "mouse"]}' AS payload_str
UNION ALL
SELECT 2 AS id, '{"user": {"id": 2, "name": "Jiro", "age": 25}, "items": ["keyboard", "monitor"]}' AS payload_str
UNION ALL
SELECT 3 AS id, '{"user": {"id": 3, "name": "Saburo", "age": 40}, "items": ["webcam"]}' AS payload_str;

-- STRING型テーブルを作成
CREATE OR REPLACE TABLE json_as_string
AS SELECT id, payload_str FROM raw_json_data;

-- VARIANT型テーブルを作成 (parse_json関数で変換)
CREATE OR REPLACE TABLE json_as_variant
AS SELECT id, parse_json(payload_str) AS payload_var FROM raw_json_data;

3.2. ステップ2: パフォーマンス比較クエリの実行

-- 【遅い】STRING型テーブルに対するクエリ
SELECT id, get_json_object(payload_str, '$.user.name') AS user_name
FROM json_as_string
WHERE CAST(get_json_object(payload_str, '$.user.age') AS INT) > 30;

-- 【速い】VARIANT型テーブルに対するクエリ
SELECT
  id,
  payload_var:user.name
FROM
  json_as_variant
WHERE
  CAST(payload_var:user.age AS INT) > 30;

3.3. ステップ3: パフォーマンスの計測と比較

クエリを実行した後、Databricks SQL Warehouseの**「クエリ履歴」** 機能を使用して、実行時間やリソース消費量を詳細に比較します。


4. 検証結果:クエリプロファイルに基づく分析

上記の手順でクエリを実行した結果、以下のクエリプロファイルが得られました。これらの結果は、VARIANT型の理論上の優位性を具体的に証明しています。

図1: STRING型テーブルのクエリプロファイル
STRING型テーブルのクエリプロファイル

図2: VARIANT型テーブルのクエリプロファイル
VARIANT型テーブルのクエリプロファイル

4.1. パフォーマンス指標の比較

両プロファイルから主要な指標を比較すると、その差は明らかです。

指標 図1: STRING型 図2: VARIANT型 改善率
総実行時間 1秒 413ミリ秒 640 ミリ秒 約2.2倍 高速化
タスクの合計時間 (CPU負荷) 108 ミリ秒 62 ミリ秒 約43% 削減
読み込みバイト数 (I/O) 1.26 KB 1.11 KB 約12% 削減

4.2. 結果の考察

  • 総実行時間: VARIANT型はSTRING型の半分以下の時間でクエリを完了しており、ユーザーが体感する速度が大幅に向上しています。
  • タスクの合計時間: これはクラスターが実際に処理を行ったCPU時間を示します。VARIANT型でCPU時間が43%も削減されたのは、高負荷な文字列解析処理 (get_json_object) が不要になり、負荷の低い直接アクセスに変わったためです。これがパフォーマンス向上の主な理由です。
  • 読み込みバイト数: VARIANT型のバイナリ形式はデータを効率的に格納するため、ストレージから読み込むデータ量そのものが少なくなっています。これによりストレージコストとI/O負荷の両方が削減されます。

この結果は、データ量が少ないテストケースであっても、アーキテクチャの違いが明確なパフォーマンス差として現れることを示しています。データが大規模になれば、この差はさらに大きくなります。

5. 参考資料

Why VARIANT Outperforms STRING for JSON Data

Discussion