メインコンテンツへスキップ

説明

Native フォーマットは、カラムを行に変換しない真の「列指向」フォーマットであるため、ClickHouse で最も効率的なフォーマットです。 このフォーマットでは、データはバイナリフォーマットで ブロック 単位に読み書きされます。 各ブロックについて、行数、カラム数、カラム名と型、さらにブロック内の各カラムのデータ部分が順に記録されます。 これは、サーバー間のやり取りに使われるネイティブインターフェイス、コマンドラインクライアント、C++ クライアントで使用されるフォーマットです。
このフォーマットを使うと、ClickHouse DBMS でのみ読み取れるダンプをすばやく生成できます。 ただし、このフォーマットを直接扱うのはあまり現実的ではないかもしれません。

データ型のワイヤ形式

データはワイヤ上で列指向フォーマットで送信されます。つまり、各カラムは個別に送信され、 1 つのカラム内のすべての値が単一の配列としてまとめて送信されます。 ブロック内の各カラムには、RowBinaryWithNamesAndTypes と同様のヘッダーがあります。
ネイティブ TCP バイナリプロトコルを使用する場合 (または HTTP エンドポイントが ?client_protocol_version=<n> を受信する場合) 、 カラム数と行数の前に BlockInfo 構造体が書き込まれます。このセクションの例では、 プロトコルバージョンを指定しない通常の HTTP インターフェイスを使用しているため、BlockInfo は省略されます。

ブロック構造

次のクエリは、numberstr の 2 つのカラムを持つ 3 行を返します:
出力データは1つのClickHouseブロックに収まり、次のようになります:

複数のブロック

ただし、多くの場合、データは1つのブロックには収まらず、ClickHouse は複数のブロックに分けて送信します。 データが1ブロックにつき1行に分割されるよう、ブロックサイズを小さくして2行を取得する次のクエリを見てみましょう。
出力:

単純なデータ型

これらの比較的単純なデータ型における個々の値のワイヤ形式は、RowBinary/RowBinaryWithNamesAndTypes と似ています。 この説明に該当する型の一覧は次のとおりです。
  • (U)Int8, (U)Int16, (U)Int32, (U)Int64, (U)Int128, (U)Int256
  • Float32, Float64
  • Bool
  • String
  • FixedString(N)
  • Date
  • Date32
  • DateTime
  • DateTime64
  • IPv4
  • IPv6
  • UUID
詳細については、“RowBinary data types wire format” にある上記の型の説明を参照してください。

複合データ型

以下の型のエンコーディングは、RowBinary および RowBinaryWithNamesAndTypes のものとは異なります。
  • Nullable
  • LowCardinality
  • Array
  • Map
  • Variant
  • Dynamic
  • JSON

Nullable

Nativeフォーマットでは、Nullableカラムでは実際のデータの前に、ブロック内の行数と同じだけのバイト列が置かれます。各バイトは、その値が NULL かどうかを示します。たとえば、このクエリでは、代わりに各奇数が NULL になります。
出力は次のようになります。
Nullable(String) でも同様です。null インジケーターは常に nullable のマスクバイトで決まり、 マスク値が 0x01 の場合は、文字列の内容に関係なくその行は NULL になります。NULL の行では、 実際の文字列は空文字列として格納されます (LEB128 の長さは 0) 。なお、NULL ではない空 文字列も LEB128 の長さは 0 なので、この 2 つのケースを区別できるのはマスクバイトだけです。たとえば、次のクエリです。
出力は以下のようになります。

LowCardinality

LowCardinality が透過的に扱われる RowBinary とは異なり、Nativeフォーマット では辞書ベースの列指向エンコーディングを使用します。カラムは、バージョンプレフィックス、一意な値の辞書、その辞書を参照する整数の索引の Array としてエンコードされます。
カラムは LowCardinality(Nullable(T)) として定義できますが、Nullable(LowCardinality(T)) として定義することはできません。常にサーバーエラーになります。
バージョンプレフィックスは値 1UInt64(LE) で、カラムごとに 1 回書き込まれます。続いて、ブロック ごとに次の内容が書き込まれます。
  • UInt64(LE)IndexesSerializationType のビットフィールド。ビット 0–7 は索引の幅を表します (0 = UInt8、1 = UInt16、2 = UInt32、3 = UInt64) 。ビット 8 (NeedGlobalDictionaryBit) は Nativeフォーマット では決して設定されません (これが現れた場合、サーバーは例外をスローします) 。ビット 9 は追加の辞書キーが存在することを示します。ビット 10 は辞書をリセットする必要があることを示します。
  • UInt64(LE) — 辞書キー数。続いて、キーが内部型のエンコーディングを使って一括シリアライゼーションされます。
  • UInt64(LE) — 行数。続いて、索引値が適切な UInt 幅を使って一括シリアライゼーションされます。
辞書には常に、索引 0 にデフォルト値が含まれます (たとえば String では空文字列、数値型では 0) 。LowCardinality(Nullable(T)) の場合、索引 0 は NULL を表し、キーは Nullable ラッパーなしでシリアライゼーションされます。 たとえば、5 行 ['foo', 'bar', 'baz', 'foo', 'bar'] を持つ LowCardinality(String) は次のように表されます。
LowCardinality(Nullable(String)) では、索引 0 は NULL になります:

Array

各配列の先頭に LEB128 形式の要素数が付く RowBinary とは異なり、Nativeフォーマットでは、配列は次の 2 つの列指向サブストリームとしてエンコードされます。
  • 累積 UInt64 オフセットが N 個 (リトルエンディアン、各 8 バイト) 。行 i の要素数は offset[i] - offset[i-1] で、offset[-1] は暗黙的に 0 とみなされます。
  • 全行にわたるすべてのネスト要素を、連続した領域にまとめて一括シリアライズします。
たとえば、3 行 [[0, 10], [1, 11], [2, 12]] を持つ Array(UInt32) の場合:
空の配列のオフセットは、前の行と同じです。たとえば、4 行の Array(String) [[], ['0'], ['0','1'], ['0','1','2']] の場合:

Map

Map(K, V)Array(Tuple(K, V)) としてエンコードされます。つまり、配列オフセットの後にすべてのキーが並び、その後にすべての値が並びます。これは、各エントリごとにキーと値が交互に格納される RowBinary とは異なります。 たとえば、3 行の Map(String, UInt64) [{'a':0,'b':10}, {'a':1,'b':11}, {'a':2,'b':12}] は次のようにエンコードされます。

Variant

各行がそれぞれ自身の discriminant バイトを持ち、その直後に値がインラインで続く RowBinary とは異なり、Nativeフォーマット では discriminant とデータが分離されています。
RowBinary と同様に、定義内の型は常にアルファベット順にソートされ、discriminant はそのソート済みリスト内の索引です。0xFF (255) は NULL を表します。
Variant カラムは次のようにエンコードされます。
  • UInt64(LE) の discriminator モード prefix (0 = BASIC、1 = COMPACT) 。Nativeフォーマット の出力では通常 BASIC (0) が使用されます。COMPACT モードは、use_compact_variant_discriminators_serialization を有効にして保存されたデータを読み取る際に現れることがあります。
  • N 個の UInt8 discriminant。各行に 1 つずつ対応します。
  • 各 Variant 型のデータは、それに一致する行だけを含む個別のバルクカラムとして、discriminant の順に格納されます。
たとえば、5 行 [0::UInt32, 'hello', NULL, 3::UInt32, 'hello'] を持つ Variant(String, UInt32) の場合 (ソート順: String = 0、UInt32 = 1) :

Dynamic

各値が自己記述的 (型プレフィックス + 値) である RowBinary とは異なり、Nativeフォーマット では Dynamic は構造プレフィックスに続く Variant カラムとしてシリアライズされます。 構造プレフィックスには、UInt64(LE) のシリアル化バージョン、動的型の数 (VarUInt として) 、続いて文字列としての型名が含まれます。バージョン V1 では、互換性のため型の数が 2 回書き込まれます。後続のデータは Variant カラムで、その型リストは動的型に内部 SharedVariant 型を加えたものをアルファベット順に並べたものです。 たとえば、5 行の [0::UInt32, 'hello', NULL, 3::UInt32, 'hello'] を持つ Dynamic の場合:

JSON

各行がパス名と値を含み自己記述的である RowBinary とは異なり、Nativeフォーマット では JSON は列指向の構造でシリアライズされます。このエンコーディングは複雑で、バージョンにも依存します。具体的には、シリアル化バージョン、動的パス名、共有データレイアウトを含む構造プレフィックスに続いて、型付きパス (それぞれをバルクカラムとして格納) 、動的パス (それぞれを Dynamic カラムとして格納) 、さらにオーバーフローパス用の共有データで構成されます。 より簡単に相互運用できるようにするには、JSON カラムを通常の JSON テキスト文字列 (各行につき 1 つの String) としてシリアライズする設定 output_format_native_write_json_as_string=1 の使用を検討してください。
最終更新日 2026年6月19日