Dynamic
このタイプは、すべての値の型を事前に知らずに格納することを可能にします。
Dynamic
型のカラムを宣言するには、次の構文を使用します。
ここで、N
はオプションのパラメータで、0
から254
の間であり、Dynamic
型のカラム内に格納される異なるデータ型の数を示します。これらのデータ型は、個別のサブカラムとして、単一のデータブロック内に別々に格納されます (例えば、MergeTreeテーブルの単一データパートで)。この制限が超えられた場合、新しい型のすべての値は、特別な共有データ構造にバイナリ形式で格納されます。max_types
のデフォルト値は32
です。
Creating Dynamic
テーブルカラム定義でDynamic
型を使用する場合:
通常のカラムからキャストを使用する場合:
Variant
カラムからキャストを使用する場合:
Reading Dynamic nested types as subcolumns
Dynamic
型は、型名をサブカラムとして使用したDynamic
カラムから単一のネストされた型を読み取ることをサポートしています。
したがって、カラムd Dynamic
を持つ場合、任意の有効な型T
のサブカラムをd.T
という構文を使用して読み取ることができます。このサブカラムは、T
がNullable
内に置くことができる場合はNullable(T)
型となり、そうでない場合はT
型となります。このサブカラムのサイズは元のDynamic
カラムと同じであり、元のDynamic
カラムに型T
が存在しないすべての行ではNULL
(またはT
がNullable
内に入れることができない場合は空の値)が含まれます。
Dynamic
サブカラムは、関数dynamicElement(dynamic_column, type_name)
を使用しても読み取ることができます。
例:
各行に格納されているバリアントを知るにはdynamicType(dynamic_column)
関数を使用できます。この関数は、各行に対して値の型名(または行がNULL
の場合は'None'
)を返します。
例:
Conversion between Dynamic column and other columns
Dynamic
カラムに対して実行可能な変換は4つあります。
Converting an ordinary column to a Dynamic column
Converting a String column to a Dynamic column through parsing
String
カラムからDynamic
型の値を解析するには、設定cast_string_to_dynamic_use_inference
を有効にします:
Converting a Dynamic column to an ordinary column
Dynamic
カラムを通常のカラムに変換することが可能です。この場合、すべてのネストされた型は宛先型に変換されます:
Converting a Variant column to Dynamic column
Converting a Dynamic(max_types=N) column to another Dynamic(max_types=K)
もしK >= N
であれば、変換の間にデータは変更されません:
もしK < N
であれば、最も稀な型の値は特別なサブカラムに挿入されますが、それでもアクセス可能です:
isDynamicElementInSharedData
関数は、特別な共有データ構造内に格納される行に対してtrue
を返します。結果のカラムは、共有データ構造に格納されていない2つのタイプのみを含むことがわかります。
もしK=0
なら、すべてのタイプは単一の特別なサブカラムに挿入されます:
Reading Dynamic type from the data
すべてのテキストフォーマット(TSV、CSV、CustomSeparated、Values、JSONEachRowなど)は、Dynamic
型の読み取りをサポートしています。データ解析中、ClickHouseは各値の型を推測し、Dynamic
カラムへの挿入時に使用します。
例:
Using Dynamic type in functions
大多数関数はDynamic
型の引数をサポートしています。この場合、関数はDynamic
カラム内に格納された各内部データ型に対して個別に実行されます。
関数の結果の型が引数の型によって変わる場合、そのような関数の結果はDynamic
になります。結果の型が引数の型に依存しない場合、結果はNullable(T)
であり、T
はこの関数の通常の結果型です。
例:
関数がDynamic
カラム内のいくつかの型で実行できない場合、例外がスローされます:
不必要な型をフィルタリングすることができます:
または、必要な型をサブカラムとして抽出することができます:
Using Dynamic type in ORDER BY and GROUP BY
ORDER BY
およびGROUP BY
で、Dynamic
型の値はVariant
型の値と同様に比較されます:
型Dynamic
の値d1
の底層型T1
と値d2
の底層型T2
に対しての演算子<
の結果は以下のように定義されます:
- もし
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
型の値は異なる値 と見なされ、互いに比較されず、型名が比較されます。
例:
注意: 比較演算子<
/ >
/ =
などの比較関数の実行中には、ここで説明された比較ルールは適用されません。これは関数での特別な動作によるものです。
Reaching the limit in number of different data types stored inside Dynamic
Dynamic
データ型は、異なるデータ型の限られた数をサブカラムとして格納できます。デフォルトでは、この制限は32
ですが、型宣言内で構文Dynamic(max_types=N)
を使用することにより変更できます。ここで、N
は0
から254
の間です(実装の詳細により、Dynamic
内の個別のサブカラムとして格納できる異なる型は254を超えることがありません)。
制限に達すると、すべての新しいデータ型は、異なるデータ型をバイナリ形式で格納する特別な共有データ構造に挿入されます。
制限に達した場合に、異なるシナリオで何が起こるかを見てみましょう。
Reaching the limit during data parsing
データからDynamic
値を解析中に、現在のデータブロックのために制限に達した場合、新しいすべての値は共有データ構造に挿入されます:
ご覧のとおり、異なる3つのデータ型Int64
、Array(Int64)
、String
を挿入した後、新しい型がすべて特別な共有データ構造に挿入されました。
During merges of data parts in MergeTree table engines
MergeTreeテーブル内の複数のデータパーツをマージする際、Dynamic
カラムは、結果のデータパート内で格納できる異なるデータ型の制限に達することがあります。その場合、ClickHouseは、どの型がマージ後も個別のサブカラムとして残り、どの型が共有データ構造に挿入されるのかを選択します。ほとんどの場合、ClickHouseは最も頻繁な型を保持し、稀な型を共有データ構造に格納しようとしますが、実装によって異なります。
そのようなマージの例を見てみましょう。まず、Dynamic
カラムを持つテーブルを作成し、異なるデータ型の制限を3
に設定し、5
つの異なるタイプの値を挿入します:
各挿入は、Dynamic
カラム内に単一の型を持つ別々のデータパートを作成します:
さて、すべてのパーツを一つにマージして、何が起こるか見てみましょう:
ご覧のとおり、ClickHouseは最も頻繁な型UInt64
およびArray(UInt64)
をサブカラムとして保持し、他のすべての型を共有データに挿入しました。
JSONExtract functions with Dynamic
すべてのJSONExtract*
関数はDynamic
型をサポートしています:
Binary output format
RowBinaryフォーマットでは、Dynamic
型の値は以下のフォーマットでシリアル化されます: