メインコンテンツまでスキップ
メインコンテンツまでスキップ

動的

Beta feature. Learn more.

このタイプは、すべての値のタイプを事前に知らなくても、任意のタイプの値をその中に格納することを可能にします。

Dynamic タイプのカラムを宣言するには、以下の構文を使用します:

ここで N は、Dynamic タイプのカラム内に別々のサブカラムとして格納できる異なるデータタイプの数を示すオプションのパラメータで、 0 から 254 の範囲内です。この制限を超えた場合、新しいタイプのすべての値は、バイナリ形式で特別な共有データ構造に一緒に格納されます。デフォルト値の max_types32 です。

注記

Dynamic データタイプはベータ機能です。使用するには、enable_dynamic_type = 1 を設定してください。

Dynamic の作成

テーブルのカラム定義で Dynamic タイプを使用するには:

通常のカラムからのキャストを使用する:

Variant カラムからのキャストを使用する:

Dynamic ネストされたタイプをサブカラムとして読み取る

Dynamic タイプは、型名をサブカラムとして使用して、Dynamic カラムから単一のネストされたタイプを読み取ることをサポートしています。 したがって、カラム d Dynamic がある場合、任意の有効なタイプ T のサブカラムを d.T 構文を使用して読み取ることができます。このサブカラムは、TNullable 内に存在できる場合は Nullable(T) 型となり、そうでなければ T 型となります。このサブカラムは、元の Dynamic カラムと同じサイズで、元の Dynamic カラムがタイプ T を持たないすべての行には NULL 値(または TNullable 内に存在できない場合は空の値)が含まれます。

Dynamic サブカラムは dynamicElement(dynamic_column, type_name) 関数を使用して読み取ることもできます。

例:

各行に格納されているバリアントを知るためには、dynamicType(dynamic_column) 関数を使用できます。各行の値タイプ名の文字列を返します(または行が NULL の場合は 'None' を返します)。

例:

Dynamic カラムと他のカラム間の変換

Dynamic カラムに対して実行できる変換は4つあります。

通常のカラムを Dynamic カラムに変換する

文字列カラムを Dynamic カラムに変換するための解析

String カラムから Dynamic タイプの値を解析するには、cast_string_to_dynamic_use_inference を設定できます:

Dynamic カラムを通常のカラムに変換する

Dynamic カラムを通常のカラムに変換することが可能です。この場合、すべてのネストされたタイプは、目的のタイプに変換されます:

Variant カラムを Dynamic カラムに変換する

Dynamic(max_types=N) カラムを他の Dynamic(max_types=K) に変換する

K >= N の場合、変換中にデータは変わりません:

K < N の場合、最も珍しいタイプの値は単一の特別なサブカラムに挿入されますが、引き続きアクセスは可能です:

isDynamicElementInSharedData 関数は、Dynamic 内の特別な共有データ構造に格納されている行に対して true を返します。結果のカラムには、共有データ構造に格納されていない2種類のタイプのみが含まれています。

K=0 の場合、すべてのタイプは単一の特別なサブカラムに挿入されます:

データから Dynamic タイプを読み取る

すべてのテキスト形式(TSV、CSV、CustomSeparated、Values、JSONEachRow など)は、Dynamic タイプの読み取りをサポートしています。データ解析中に、ClickHouse は各値のタイプを推測して、それを Dynamic カラムへの挿入に使用しようとします。

例:

Dynamic タイプを関数で使用する

ほとんどの関数は Dynamic タイプの引数をサポートします。この場合、関数は、Dynamic カラムに格納された内部データタイプそれぞれに対して別々に実行されます。 関数の結果タイプが引数タイプに依存する場合、そのような関数の Dynamic 引数を使用して実行された結果は Dynamic になります。結果のタイプが引数のタイプに依存しない場合、結果は Nullable(T) になります、ここで T はこの関数の通常の結果タイプです。

例:

関数が Dynamic カラム内のいくつかのタイプに対して実行できない場合、例外がスローされます:

不要なタイプをフィルタリングすることができます:

あるいは、必要なタイプをサブカラムとして抽出します:

Dynamic タイプを使用した ORDER BY や GROUP BY

ORDER BY および GROUP BY において、Dynamic タイプの値は Variant タイプの値と同様に比較されます: 値 d1 の基になるタイプが T1 で、値 d2 の基になるタイプが T2Dynamic の間の < 演算子の結果は次のように定義されます:

  • T1 = T2 = T の場合、結果は d1.T < d2.T となり(基の値が比較されます)。
  • T1 != T2 の場合、結果は T1 < T2 となります(型名が比較されます)。

デフォルトでは、Dynamic タイプは GROUP BY/ORDER BY キーで使用できません。使用したい場合は、その特別な比較ルールを考慮し、allow_suspicious_types_in_group_by / allow_suspicious_types_in_order_by 設定を有効にしてください。

例:

注: 異なる数値型を持つ動的タイプの値は異なる値と見なされ、お互いに比較されません。それらのタイプ名が比較されます。

例:

注意: 記載された比較ルールは、< / > / = などの比較関数の実行時には適用されません。これは、Dynamic 型を使用する関数の特別な動作によるものです。

動的内に異なるデータ型の数の制限に達する

Dynamic データタイプは、別々のサブカラムとして格納できる異なるデータタイプの限られた数しか保存できません。デフォルトでは、この制限は32ですが、Dynamic(max_types=N) 構文を使用して型宣言で変更できます。ここで N0 から 254 の間です(実装の詳細により、Dynamic 内に異なるデータ型が254を超えて保存されることは不可能です)。 制限に達した場合、新しく挿入されたすべてのデータ型は、バイナリ形式で異なるデータ型の値を格納する単一の共有データ構造に挿入されます。

制限に達したときに異なるシナリオで何が起こるかを見てみましょう。

データ解析中に制限に達する

データから Dynamic 値を解析中に、現在のデータブロックの制限が達された場合、新しいすべての値は共有データ構造に挿入されます:

3つの異なるデータタイプ Int64Array(Int64)String を挿入した後、他のすべての新しいタイプは特別な共有データ構造に挿入されたことがわかります。

MergeTree テーブルエンジンのデータパーツのマージ中に

MergeTree テーブルでいくつかのデータパーツをマージする際、結果のデータパート内の Dynamic カラムは、異なるサブカラムとして格納できる異なるデータタイプの制限に達する可能性があります。これは、ソースパーツからのすべてのタイプをサブカラムとして保存できません。 この場合、ClickHouse は、マージ後にどのタイプがサブカラムとして残るか、そしてどのタイプが共有データ構造に挿入されるかを決定します。ほとんどの場合、ClickHouse は最も一般的なタイプを保持し、珍しいタイプを共有データ構造に保存しようとしますが、これは実装によって異なります。

そのようなマージの例を見てみましょう。まず、Dynamic カラムを持つテーブルを作成し、異なるデータタイプの制限を 3 に設定して、5 つの異なるタイプの値を挿入します:

各挿入は、単一のタイプを含む Dynamic カラムを持つ別のデータパートを作成します:

次に、すべてのパートを1つにマージし、何が起こるか見てみましょう:

ClickHouse が最も一般的なタイプ UInt64Array(UInt64) をサブカラムとして保持し、他のすべてのタイプを共有データ構造に挿入したことがわかります。

Dynamic を用いた JSONExtract 関数

すべての JSONExtract* 関数は Dynamic タイプをサポートします:

バイナリ出力形式

RowBinary 形式では、Dynamic タイプの値は次の形式でシリアライズされます: