JSONカラム型は ClickHouse 25.3+ から本番環境で利用可能です。これより前のバージョンは本番利用には推奨されません。
クイック判断
- すべてのフィールド の型が既知かつ安定しており、スキーマもほとんど変わらない場合 → 型付きカラム
- ほとんどのフィールド は安定しているものの、一部が動的または予測しにくい場合 → ハイブリッド (typed + JSON)
- 構造全体 が動的で、レコードごとに現れたり消えたりするキーがある場合 → ネイティブ JSON カラム
- 動的フィールド がキー・バリューのペアで、値の型が一貫している場合 (例: 文字列のタグ、数値メトリクス)
→ JSON ではなく
Map - JSONブロブ を保存・取得するだけで、フィールドレベルのクエリ を行わない場合 → 不透明な String ストレージ
JSON フォーマット と JSON カラム型 を混同しないでください。
JSON カラム型をまったく使わなくても、JSON形式のデータ (JSONEachRow など) を typed columns に挿入できます。ここでの判断対象は input format ではなく、カラム型です。アプローチの詳細
型付きカラム
Array、Tuple、Nested 型で表現できます。
トレードオフ: スキーマの変更には ALTER TABLE が必要です。想定外のフィールドは、スキーマを更新しない限り、INSERT 時にエラーなく破棄されます。
セットアップ、検証、注意点
セットアップ、検証、注意点
セットアップ検証注意点
JSONEachRowで JSON データを insert する際、その JSON にスキーマに存在しないフィールドが含まれている場合、ClickHouse は既定でそれらをエラーなく破棄します。代わりにエラーにしたい場合は、input_format_skip_unknown_fieldsを0に設定してください。
ハイブリッド (型付きカラム + JSON)
セットアップ、検証、注意点
セットアップ、検証、注意点
セットアップ検証注意点
- あらかじめ把握している JSONパス には 型ヒント を使ってください。型ヒントを使うと判別子カラムを介さず、そのパスは通常の型付きカラムと同じように格納され、同等のパフォーマンスが得られ、オーバーヘッドも発生しません。
- クエリしないパス (デバッグ用メタデータ、内部 tracing ID など) には
SKIPまたはSKIP REGEXPを使い、ストレージを節約して subcolumn 数を減らしてください。 max_dynamic_pathsは、実際にクエリする distinct path の数に応じて設定してください。デフォルト値 (1024) はほとんどのケースで十分です。動的な部分が小さい場合は、より低い値にしてください。max_dynamic_pathsを 10,000 より大きく設定しないでください。値を大きくしすぎると resource 消費が増え、効率が低下します。
ドット付きキードットを含むキー (例:
http.status_code) は、デフォルトではネストされたパスとして扱われるため、{"http.status_code": 200} は {"http": {"status_code": 200}} と同じ形で格納されます。これは OTel の属性で一般的です。型ヒントを使ってドット付きパスの格納方法を制御するか、json_type_escape_dots_in_keys (25.8+) を有効にしてください。ネイティブ JSON カラム
セットアップ、検証、注意点
セットアップ、検証、注意点
セットアップJSON カラムに JSON ドキュメント全体を挿入する場合は、注意事項
JSONAsObject フォーマットを使用します。各入力行を、カラムにマッピングされる完全な JSON オブジェクトとして扱います。検証- 型ヒントがない場合、ClickHouse は最初に確認した値をもとにパスごとに型を推論します。あるレコードでは
scoreが"10"(文字列) として届き、別のレコードでは10(整数) として届くと、そのパスには判別子カラムが作成され、クエリが遅くなります。型が分かっているパスにはヒントを追加してください。 - パス数が
max_dynamic_pathsを超えると、overflow 値はクエリパフォーマンスが低下する 共有データ構造 に移されます。JSONDynamicPaths()で監視し、上限は 10,000 未満に保ってください。 - 各動的パスは、最大
max_dynamic_types(デフォルトは 32) の異なるデータ型をサポートします。1 つのパスがこれを超えると、追加の型は共有 variant ストレージにフォールバックします。これは、同じフィールドで型の不一致が非常に多いデータでない限り、問題になることはほとんどありません。
不透明な String ストレージ
JSONExtract ファミリーを使う) 以外にフィールドレベルのクエリはできず、これを大規模に行うと低速です。
セットアップ、検証、注意点
セットアップ、検証、注意点
セットアップ検証注意点
- 要件が変わって後からフィールド単位のクエリが必要になった場合は、型付きカラムまたは JSON カラムを持つ新しいテーブルを作成し、データをバックフィルする必要があります。個々のフィールドをクエリする可能性が少しでもあるなら、代わりにハイブリッド方式から始めてください。
JSONExtract関数は、クエリのたびに文字列をパースします。アドホックな調査には許容できますが、本番のダッシュボードや高 QPS のワークロードには向きません。- JSON ペイロードが大きい場合は、String カラムに圧縮 codec (
ZSTD) を使うことを検討してください。高い圧縮効果が得られます。
比較
Map のほうが適している場合
Map(String, T) のほうがシンプルで効率的です。一般的な例としては、文字列タグ (Map(String, String)) 、数値メトリクス (Map(String, Float64)) 、機能フラグ (Map(String, Bool)) があります。
Map はキー単位のフィルタリング (tags['env'] = 'prod') をサポートし、JSON より低コストで保存でき、JSON type のサブカラムによるオーバーヘッドも回避できます。なお、デフォルトではキーのルックアップ時に Map が線形スキャンされます。小規模なタグセットであれば問題ありませんが、100 個以上のキーを持つ map では with_buckets シリアライゼーション を検討してください。値の型が混在している場合や構造がネストしている場合は JSON を使用し、フラットなキー・バリューのペアで値の型が uniform な場合は Map を使用してください。
- Use JSON where appropriate — JSON カラム型を代替手段と比較して、どのような場合に使うべきか
- JSON data type リファレンス — 型ヒント、SKIP、max_dynamic_paths、イントロスペクション関数の完全な構文
- データ型の選び方 — データ型を選ぶ際の一般的なガイダンス
- ClickHouse の新しい強力な JSON データ型 — JSON 型のストレージアーキテクチャを詳しく解説
- JSON フォーマットのリファレンス — JSON データ用の入出力フォーマット (JSONEachRow、JSONAsObject など)