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

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という構文を使用して読み取ることができます。このサブカラムは、TNullable内に置くことができる場合はNullable(T)型となり、そうでない場合はT型となります。このサブカラムのサイズは元のDynamicカラムと同じであり、元のDynamicカラムに型Tが存在しないすべての行ではNULL(またはTNullable内に入れることができない場合は空の値)が含まれます。

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 BYORDER 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)を使用することにより変更できます。ここで、N0から254の間です(実装の詳細により、Dynamic内の個別のサブカラムとして格納できる異なる型は254を超えることがありません)。 制限に達すると、すべての新しいデータ型は、異なるデータ型をバイナリ形式で格納する特別な共有データ構造に挿入されます。

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

Reaching the limit during data parsing

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

ご覧のとおり、異なる3つのデータ型Int64Array(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型の値は以下のフォーマットでシリアル化されます: