MergeTree
MergeTree
エンジンおよび MergeTree
ファミリーの他のエンジン(例: ReplacingMergeTree
, AggregatingMergeTree
)は、ClickHouse で最も一般的に使用され、最も堅牢なテーブルエンジンです。
MergeTree
ファミリーのテーブルエンジンは、高いデータ取り込み率と巨大なデータボリュームを想定して設計されています。
挿入操作は、バックグラウンドプロセスによって他のテーブルパーツとマージされるテーブルパーツを作成します。
MergeTree
ファミリーのテーブルエンジンの主な特徴。
-
テーブルの主キーは、各テーブルパーツ内のソート順を決定します(クラスタインデックス)。主キーは、個々の行ではなく、8192 行のブロックであるグラニュールを参照します。これにより、大規模データセットの主キーはメインメモリに保持されるのに十分小さく、ディスク上のデータに迅速にアクセスできます。
-
テーブルは任意のパーティション式を使用してパーティショニングできます。クエリが許可される場合、パーティションプルーニングは読取時にパーティションを省略します。
-
データは、高可用性、フェイルオーバー、ゼロダウンタイムアップグレードのために、複数のクラスター ノード間でレプリケートできます。詳細は データレプリケーション を参照してください。
-
MergeTree
テーブルエンジンは、クエリの最適化を助けるために、さまざまな統計の種類とサンプリング方法をサポートしています。
同名ですが、 Merge エンジンは *MergeTree
エンジンとは異なります。
テーブルの作成
パラメータの詳細な説明については、CREATE TABLE ステートメントを参照してください。
クエリ句
ENGINE
ENGINE
— エンジンの名前とパラメータ。 ENGINE = MergeTree()
。MergeTree
エンジンにはパラメータはありません。
ORDER BY
ORDER BY
— ソートキー。
カラム名または任意の式のタプル。例: ORDER BY (CounterID + 1, EventDate)
。
主キーが定義されていない場合(つまり、PRIMARY KEY
が指定されていない場合)、ClickHouse はソートキーを主キーとして使用します。
ソートが不要な場合は、構文 ORDER BY tuple()
を使用できます。
設定 create_table_empty_primary_key_by_default
が有効になっている場合は、ORDER BY tuple()
が CREATE TABLE
ステートメントに暗黙的に追加されます。詳細は 主キーの選択 を参照してください。
PARTITION BY
PARTITION BY
— パーティショニングキー。オプション。ほとんどの場合、パーティションキーは必要ありません。必要な場合でも、通常、月単位でパーティションするよりも詳細なパーティションキーは必要ありません。パーティショニングはクエリの速度を上げません(ORDER BY
式とは対照的に)。過度に詳細なパーティショニングを使用すべきではありません。クライアント識別子や名前でデータをパーティションしないでください(その代わり、ORDER BY
式の最初のカラムとしてクライアント識別子または名前を指定してください)。
月ごとのパーティショニングには、toYYYYMM(date_column)
表現を使用します。ここで date_column
は、Date 型の日付を持つカラムです。ここでのパーティション名は "YYYYMM"
形式を持ちます。
PRIMARY KEY
PRIMARY KEY
— ソートキーと異なる場合の主キーです。オプション。
ソートキーを指定することは(ORDER BY
句を使用)、暗黙的に主キーを指定することになります。
通常、ソートキーに加えて主キーを指定する必要はありません。
SAMPLE BY
SAMPLE BY
— サンプリング式。オプション。
指定した場合は、主キーに含まれている必要があります。 サンプリング式は符号なし整数を生成する必要があります。
例: SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))
。
TTL
TTL
— 行の保存期間と、自動的なパーツの移動のロジックを指定する規則のリスト ディスク間とボリューム間での。オプション。
式は Date
または DateTime
を生成する必要があり、例: TTL date + INTERVAL 1 DAY
です。
規則のタイプ DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'|GROUP BY
は、式が満たされたときにパーツで行われる動作を指定します(現在の時間に達したとき):期限切れ行の削除、指定されたディスク(TO DISK 'xxx'
)またはボリューム(TO VOLUME 'xxx'
)へのパーツの移動、または期限切れ行の値の集約。規則のデフォルトのタイプは削除(DELETE
)です。複数の規則を指定できますが、DELETE
規則は 1 つだけにしてください。
詳細については、列およびテーブルの TTL を参照してください。
SETTINGS
セクション設定の例
この例では、月ごとのパーティショニングを設定しました。
また、ユーザー ID によるハッシュとしてサンプリングの式も設定しました。これにより、各 CounterID
と EventDate
に対してテーブルのデータを擬似的にランダム化できます。データを選択する際にSAMPLE句を定義すると、ClickHouse はユーザーのサブセットに対して均等に擬似的なランダムデータサンプルを返します。
index_granularity
設定は 8192 がデフォルト値のため、省略することができます。
テーブルを作成するための非推奨メソッド
新しいプロジェクトではこのメソッドを使用しないでください。可能であれば、古いプロジェクトを上記のメソッドに切り替えてください。
MergeTree() パラメータ
date-column
— Date 型のカラムの名前。ClickHouse はこのカラムに基づいて月ごとのパーティションを自動的に作成します。パーティション名は"YYYYMM"
形式です。sampling_expression
— サンプリングのための式。(primary, key)
— 主キー。タイプ: Tuple()index_granularity
— インデックスの粒度。インデックスの「マーク」間のデータ行の数。値 8192 はほとんどのタスクに適しています。
例
MergeTree
エンジンは、上記の例のようにメインエンジンの設定メソッドと同じ方法で構成されます。
データストレージ
テーブルは、主キーによってソートされたデータパーツで構成されています。
テーブルにデータが挿入されると、独立したデータパーツが作成され、各パーツは主キーによって辞書式にソートされます。たとえば、主キーが (CounterID, Date)
の場合、パーツ内のデータは CounterID
でソートされ、各 CounterID
の中で Date
で順序付けられます。
異なるパーティションに属するデータは、異なるパーツに分けられます。ClickHouse はバックグラウンドで、データパーツをより効率的にストレージにマージします。異なるパーティションに属するパーツはマージされません。マージメカニズムは、同じ主キーを持つすべての行が同じデータパーツに存在することを保証するものではありません。
データパーツは Wide
または Compact
フォーマットで保存できます。Wide
フォーマットでは、各カラムがファイルシステム内の別のファイルに保存され、Compact
フォーマットでは、すべてのカラムが 1 つのファイルに保存されます。Compact
フォーマットは、小さく頻繁な挿入のパフォーマンスを向上させるために使用できます。
データ保存フォーマットは、テーブルエンジンの min_bytes_for_wide_part
および min_rows_for_wide_part
設定によって制御されます。データパーツ内のバイト数または行数が、対応する設定の値よりも少ない場合、パーツは Compact
フォーマットで保存されます。それ以外の場合は、Wide
フォーマットで保存されます。これらの設定がいずれも設定されていない場合、データパーツは Wide
フォーマットで保存されます。
各データパーツは、論理的にグラニュールに分けられます。グラニュールは、ClickHouse がデータを選択する際に読み取る最小の分割可能なデータセットです。ClickHouse は行や値を分割しないため、各グラニュールは常に整数数の行を含みます。グラニュールの最初の行は、その行の主キーの値でマークされます。ClickHouse は各データパーツについて、マークを保存するインデックスファイルを作成します。プライマリーキーに含まれるかどうかに関係なく、各カラムについて、ClickHouse は同じマークも保存します。これらのマークにより、カラムファイル内のデータを直接見つけることができます。
グラニュールのサイズは、テーブルエンジンの index_granularity
および index_granularity_bytes
設定によって制限されます。グラニュール内の行の数は、行のサイズに応じて [1, index_granularity]
の範囲に配置されます。1 行のサイズが設定の値を超えている場合、グラニュールのサイズは index_granularity_bytes
を超えることがあります。この場合、グラニュールのサイズは行のサイズに等しくなります。
主キーとインデックスのクエリでの使用
例として (CounterID, Date)
主キーを考えてみましょう。この場合、ソートとインデックスは次のように示すことができます:
データクエリが次のように指定されている場合:
CounterID in ('a', 'h')
の場合、サーバーはマークの範囲[0, 3)
と[6, 8)
のデータを読み取ります。CounterID IN ('a', 'h') AND Date = 3
の場合、サーバーはマークの範囲[1, 3)
と[7, 8)
のデータを読み取ります。Date = 3
の場合、サーバーはマークの範囲[1, 10]
のデータを読み取ります。
上記の例は、インデックスを使用する方が常にフルスキャンよりも効果的であることを示しています。
スパースインデックスは、追加のデータを読み取ることができます。主キーの単一範囲を読み取る場合、各データブロック内で最大 index_granularity * 2
の追加行を読み取ることができます。
スパースインデックスは、非常に多くのテーブル行と一緒に作業するのを可能にします。なぜなら、ほとんどの場合、これらのインデックスはコンピュータの RAM に収まるからです。
ClickHouse では、ユニークな主キーは必要ありません。同じ主キーを持つ複数の行を挿入できます。
PRIMARY KEY
および ORDER BY
句で Nullable
型の式を使用できますが、強く推奨されません。この機能を許可するには、allow_nullable_key 設定をオンにします。NULLS_LAST の原則は、ORDER BY
句の NULL
値に適用されます。
主キーの選択
主キー内のカラムの数に明示的な制限はありません。データ構造に応じて、主キーにより多くのカラムを含めることができます。これは次のことをもたらします:
-
インデックスのパフォーマンスを向上させる。
主キーが
(a, b)
の場合、別のカラムc
を追加すると次の条件が満たされる場合にパフォーマンスが向上します:- カラム
c
に条件があるクエリがある。 (a, b)
の値が同じ長いデータ範囲(index_granularity
の数倍長い)が一般的です。別のカラムを追加することで、かなり長いデータ範囲をスキップできる場合です。
- カラム
-
データ圧縮を改善する。
ClickHouse はデータを主キーでソートするため、一貫性が高いほど圧縮がよくなります。
-
CollapsingMergeTree や SummingMergeTree エンジンでデータ部分をマージする際の追加ロジックを提供します。
この場合、主キーとは異なる ソーティングキー を指定することが理にかなっています。
長い主キーは、挿入パフォーマンスやメモリ消費に悪影響を与えますが、主キー内の追加カラムは SELECT
クエリ中の ClickHouse のパフォーマンスに影響を与えません。
ORDER BY tuple()
構文を使用して主キーなしでテーブルを作成できます。この場合、ClickHouse は挿入順序でデータを保存します。INSERT ... SELECT
クエリでデータを挿入する際にデータ順序を保存したい場合は、max_insert_threads = 1 を設定します。
初期の順序でデータを選択するには、シングルスレッド SELECT
クエリを使用します。
ソーティングキーとは異なる主キーの選択
主キー(インデックスファイルに各マークの値を書き込む式)をソートキー(データ部分の行をソートする式)とは異なるように指定することができます。この場合、主キー式のタプルはソートキー式のタプルの接頭辞でなければなりません。
この機能は、SummingMergeTree および AggregatingMergeTree テーブルエンジンを使用する際に役立ちます。これらのエンジンを使用する一般的なケースでは、テーブルには 次元 と 測定 の 2 種類のカラムがあります。典型的なクエリは、次元でフィルタリングしながら、任意の GROUP BY
で測定カラムの値を集約します。SummingMergeTree と AggregatingMergeTree は、同じソートキーの値を持つ行を集約するため、すべての次元を追加することが自然です。その結果、キー式は長いカラムのリストで構成され、このリストは新しく追加された次元で頻繁に更新する必要があります。
この場合、効率的な範囲スキャンを提供する主キーには少数のカラムを残し、残りの次元のカラムをソートキーのタプルに追加することが理にかなっています。
ソートキーの ALTER は軽量な操作であり、新しいカラムがテーブルとソートキーに同時に追加されるとき、既存のデータパーツは変更する必要がありません。古いソートキーが新しいソートキーの接頭辞であり、新しく追加されたカラムにデータがないため、テーブルの修正時にはデータは古いソートキーと新しいソートキーの両方でソートされます。
クエリでのインデックスとパーティションの使用
SELECT
クエリでは、ClickHouse はインデックスの使用が可能かどうかを分析します。インデックスは、WHERE/PREWHERE
句が等号または不等号の比較操作を表す式(結合要素の 1 つまたはすべて)を持つ場合、または主キーまたはパーティショニングキーのカラムまたは式に対して特定の接頭辞を持つ IN
または LIKE
を持つ場合、またはこれらのカラムの特定の部分的に繰り返しを持つ関数や論理関係の式を持つ場合に使用できます。
したがって、主キーの 1 つまたは複数の範囲でクエリを迅速に実行することができます。この例では、特定のトラッキングタグ、特定のタグと日付範囲、特定のタグと日付、複数のタグと日付範囲などについてクエリを実行するときに、クエリは迅速に実行されます。
次のように構成されたエンジンを見てみましょう:
この場合、クエリでは:
ClickHouse は、主キーインデックスを使用して不適切なデータを削減し、月ごとのパーティショニングキーを使用して不適切な日付範囲にあるパーティションを削減します。
上記のクエリは、インデックスが複雑な式でも使用されることを示しています。テーブルからの読み込みは、インデックスを使用するのがフルスキャンよりも遅くなることはありません。
以下の例で、インデックスは使用できません。
クエリ実行時に ClickHouse がインデックスを使用できるかどうかを確認するには、force_index_by_date および force_primary_key の設定を使用します。
月ごとのパーティショニングキーは、適切な範囲を持つ日付を含むデータブロックのみを読み取ります。この場合、データブロックには多くの日付(最大で 1 か月分)のデータが含まれている可能性があります。ブロック内でデータは主キーでソートされていますが、主キーの最初のカラムとして日付を含まない可能性があります。このため、主キー接頭辞を指定しない単一日付条件のクエリを使用すると、単一の日付の場合よりも多くのデータが読み取られることになります。
部分的に単調増加する主キーに対するインデックスの利用
例えば、月の日を考えます。これは 1 か月の間、単調増加シーケンス を形成しますが、より長い期間に対しては単調ではありません。これは部分的に単調増加するシーケンスです。ユーザーが部分的に単調増加する主キーでテーブルを作成した場合、ClickHouse は通常のようにスパースインデックスを作成します。ユーザーがこの種のテーブルからデータを選択すると、ClickHouse はクエリ条件を分析します。インデックスの 2 つのマークの間にデータを取得したい場合、これらの 2 つのマークが 1 か月の間に収まる場合、ClickHouse はこの特定のケースでインデックスを使用できる可能性があります。なぜなら、クエリのパラメータとインデックスのマーク間の距離を計算できるからです。
クエリパラメーターの範囲の主キーの値が単調増加のシーケンスを表さない場合、ClickHouse はインデックスを使用できません。この場合、ClickHouse はフルスキャン方式を使用します。
ClickHouse はこのロジックを、月の日のシーケンスだけでなく、部分的に単調増加する任意のシーケンスの主キーに対して使用します。
データスキッピングインデックス
インデックス宣言は、CREATE
クエリのカラムセクションにあります。
*MergeTree
ファミリーのテーブルの場合、データスキッピングインデックスを指定できます。
これらのインデックスは、指定された式に関する情報を granularity_value
グラニュール(グラニュールのサイズはテーブルエンジンの index_granularity
設定を使用して指定されます)で構成されるブロックで集約します。次に、これらの集約が SELECT
クエリで使用され、クエリが満たされない大きなデータブロックをスキップするために必要なデータ量を削減します。
GRANULARITY
句は省略可能で、デフォルトの granularity_value
の値は 1 です。
例
この例のインデックスは、ClickHouse が次のクエリでディスクから読み取るデータの量を削減するために使用できます:
データスキッピングインデックスは、合成カラムに対しても作成できます:
利用可能なインデックスの種類
MinMax
指定された式の極端値を保存します(式が tuple
の場合、それぞれの tuple
の要素の極端値を保存します)。主キーのように、データブロックをスキップするために保存された情報を使用します。
構文: minmax
Set
指定された式のユニークな値を保存します(max_rows
行を超えない、 max_rows=0
は「制限なし」を意味します)。これらの値を使用して、データブロックで WHERE
式が満たされないかどうかを確認します。
構文: set(max_rows)
Bloom フィルター
指定されたカラムに対する Bloom フィルター を保存します。オプションの false_positive
パラメータは 0 から 1 の間の値で、フィルターから偽陽性の応答を受け取る確率を指定します。デフォルト値: 0.025。サポートされているデータ型: Int*
, UInt*
, Float*
, Enum
, Date
, DateTime
, String
, FixedString
, Array
, LowCardinality
, Nullable
, UUID
および Map
。Map
データ型の場合、クライアントはmapKeysまたはmapValues関数を使用して、インデックスがキーまたは値に対して作成されるべきかを指定できます。
構文: bloom_filter([false_positive])
N-gram Bloom フィルター
すべての n-gram をデータブロックから含む Bloom フィルター を保存します。データ型: String, FixedString および Map のみで使用できます。EQUALS
、 LIKE
および IN
式の最適化に使用できます。
構文: ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
n
— ngramサイズ、size_of_bloom_filter_in_bytes
— バイト単位の Bloom フィルターサイズ(例えば、256 や 512 などの大きな値を指定できます。圧縮がうまくできるため)。number_of_hash_functions
— Bloom フィルターで使用されるハッシュ関数の数。random_seed
— Bloom フィルターのハッシュ関数のシード。
ユーザーは UDF を作成して、ngrambf_v1
のパラメータセットを推定できます。クエリステートメントは次のとおりです:
これらの関数を使用するには、少なくとも 2 つのパラメータを指定する必要があります。 たとえば、グラニュール内に 4300 の ngram があり、偽陽性が 0.0001 未満であると予想される場合、次のクエリを実行して他のパラメータを推定できます:
もちろん、他の条件でパラメータを推定するためにこれらの関数を使用することもできます。 関数はこちらのコンテンツを参照します。
トークン Bloom フィルター
ngrambf_v1
と同様ですが、n-gram の代わりにトークンを保存します。トークンは、非英数字で区切られたシーケンスです。
構文: tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
特殊目的
Functions Support
WHERE
句の条件は、カラムを操作する関数の呼び出しを含みます。カラムがインデックスの一部である場合、ClickHouseは関数を実行する際にこのインデックスを使用しようとします。ClickHouseは、インデックスを使用するためのさまざまな関数のサブセットをサポートしています。
set
タイプのインデックスはすべての関数で使用できます。他のインデックスタイプは以下のようにサポートされています:
関数(演算子) / インデックス | 主キー | minmax | ngrambf_v1 | tokenbf_v1 | bloom_filter | full_text |
---|---|---|---|---|---|---|
equals (=, ==) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
notEquals(!=, <>) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
like | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
notLike | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
match | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
startsWith | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
endsWith | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
multiSearchAny | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ |
in | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
notIn | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
less (< ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
greater (> ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
lessOrEquals (<= ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
greaterOrEquals (>= ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
empty | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
notEmpty | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
has | ✗ | ✗ | ✔ | ✔ | ✔ | ✔ |
hasAny | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ |
hasAll | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ |
hasToken | ✗ | ✗ | ✗ | ✔ | ✗ | ✔ |
hasTokenOrNull | ✗ | ✗ | ✗ | ✔ | ✗ | ✔ |
hasTokenCaseInsensitive (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ |
hasTokenCaseInsensitiveOrNull (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ |
定数引数がngramサイズ未満の場合、ngrambf_v1
によるクエリ最適化には使用できません。
(*) hasTokenCaseInsensitive
とhasTokenCaseInsensitiveOrNull
を有効にするには、tokenbf_v1
インデックスを小文字化されたデータで作成する必要があります。例えば、INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0)
のようにします。
ブルームフィルターは誤陽性の一致を持つ可能性があるため、ngrambf_v1
、tokenbf_v1
、およびbloom_filter
インデックスは、関数の結果がfalseであることが期待されるクエリの最適化には使用できません。
例えば:
- 最適化可能なもの:
s LIKE '%test%'
NOT s NOT LIKE '%test%'
s = 1
NOT s != 1
startsWith(s, 'test')
- 最適化不可能なもの:
NOT s LIKE '%test%'
s NOT LIKE '%test%'
NOT s = 1
s != 1
NOT startsWith(s, 'test')
Projections
プロジェクションは物化ビューのようですが、パートレベルで定義されています。それは、一貫性の保証を提供し、クエリに自動的に使用されます。
プロジェクションを実装する際には、force_optimize_projection設定も考慮するべきです。
プロジェクションは、FINAL修飾子を持つSELECT
文ではサポートされていません。
Projection Query
プロジェクションクエリは、プロジェクションを定義するものです。それは暗黙的に親テーブルからデータを選択します。 構文
プロジェクションは、ALTER文を使用して変更または削除できます。
Projection Storage
プロジェクションはパートディレクトリ内に格納されます。これはインデックスに似ていますが、匿名のMergeTree
テーブルのパートを格納するサブディレクトリを含みます。このテーブルはプロジェクションの定義クエリによって誘導されます。GROUP BY
句がある場合、基盤のストレージエンジンはAggregatingMergeTreeとなり、すべての集約関数はAggregateFunction
に変換されます。ORDER BY
句がある場合、MergeTree
テーブルはそれを主キー式として使用します。マージプロセス中、プロジェクションパートはそのストレージのマージルーチンを介してマージされます。親テーブルのパートのチェックサムは、プロジェクションのパートと組み合わされます。他のメンテナンス作業はデータスキッピングインデックスに似ています。
Query Analysis
- プロジェクションが与えられたクエリに応じて使用されるかを確認します。つまり、基礎テーブルをクエリした場合と同じ答えが生成されるかを確認します。
- 読み取りに最も少ない粒を含む、最良の利用可能な一致を選択します。
- プロジェクションを使用するクエリパイプラインは、元のパーツを使用するものと異なります。プロジェクションがいくつかのパーツに欠けている場合、そのパイプラインを追加して動的に「プロジェクト」することができます。
Concurrent Data Access
同時テーブルアクセスのために、マルチバージョンを使用します。別の言い方をすれば、テーブルが同時に読み取られ、更新されるとき、データはクエリの時点での現在の一連のパーツから読み取られます。長時間のロックはありません。挿入は読み取り操作の妨げになりません。
テーブルからの読み取りは自動的に並列化されます。
TTL for Columns and Tables
値の寿命を決定します。
TTL
句はテーブル全体、および各個別のカラムに設定できます。テーブルレベルのTTL
は、自動的にデータをディスクやボリューム間で移動するロジックや、すべてのデータが期限切れになったパーツを再圧縮することを指定できます。
式はDateまたはDateTimeデータ型に評価される必要があります。
構文
カラムのTTLを設定する:
interval
を定義するには、時間間隔演算子を使用します。例えば:
Column TTL
カラム内の値が期限切れになると、ClickHouseはそれらをカラムデータ型のデフォルト値に置き換えます。データ部分内のすべてのカラム値が期限切れになると、ClickHouseはこのカラムをファイルシステムのデータ部分から削除します。
TTL
句はキーカラムには使用できません。
例
TTL
でテーブルを作成する:
既存のテーブルのカラムにTTLを追加する
カラムのTTLを変更する
Table TTL
テーブルには期限切れ行を削除するための式が含まれ、複数の式がディスクまたはボリューム間の部品の自動移動を可能にします。テーブル内の行が期限切れになると、ClickHouseはすべての対応する行を削除します。部分の移動や再圧縮の場合、パートのすべての行がTTL
式の条件を満たす必要があります。
TTLルールのタイプは各TTL式に続く場合があります。それは式が満たされたときに実行されるアクションに影響します(現在の時間に達すると):
DELETE
- 期限切れ行を削除(デフォルトのアクション);RECOMPRESS codec_name
-codec_name
でデータパートを再圧縮します;TO DISK 'aaa'
- 部品をディスクaaa
に移動します;TO VOLUME 'bbb'
- 部品をディスクbbb
に移動します;GROUP BY
- 期限切れ行を集約します。
DELETE
アクションは、フィルタ条件に基づいて期限切れ行の一部のみを削除するためにWHERE
句と一緒に使用できます:
GROUP BY
式はテーブルの主キーのプレフィックスでなければなりません。
カラムがGROUP BY
式の一部でなく、SET
句で明示的に設定されていない場合、結果行にはグループ化された行からの偶発的な値が含まれます(集約関数any
がそれに適用されているかのように)。
例
TTL
でテーブルを作成する:
テーブルのTTL
を変更する:
1か月後に期限切れになる行を持つテーブルを作成します。期限切れの行は日付が月曜日のときに削除されます:
期限切れ行が再圧縮されるテーブルを作成する:
期限切れ行が集約されるテーブルを作成します。結果行のx
はグループ化された行の中で最大値を持ち、y
は最小値、d
はグループ化された行からの偶発的な値を持ちます。
Removing Expired Data
期限切れのTTL
を持つデータは、ClickHouseがデータパーツをマージするときに削除されます。
ClickHouseがデータが期限切れであることを検出した場合、スケジュール外のマージを実行します。そのようなマージの頻度を制御するには、merge_with_ttl_timeout
を設定できます。値が低すぎると、多くのスケジュール外のマージが行われる可能性があり、リソースを多く消費することがあります。
マージの間にSELECT
クエリを実行すると、期限切れのデータが取得されることがあります。それを避けるためには、SELECT
の前にOPTIMIZEクエリを使用してください。
参照
Disk types
ローカルブロックデバイスに加えて、ClickHouseは次のストレージタイプをサポートしています:
s3
for S3 and MinIOgcs
for GCSblob_storage_disk
for Azure Blob Storagehdfs
for HDFSweb
for read-only from webcache
for local cachings3_plain
for backups to S3s3_plain_rewritable
for immutable, non-replicated tables in S3
Using Multiple Block Devices for Data Storage
Introduction
MergeTree
ファミリーのテーブルエンジンは、複数のブロックデバイスにデータを保存することができます。例えば、特定のテーブルのデータが暗黙的に「ホット」と「コールド」に分割されている場合に役立ちます。最新のデータは定期的にリクエストされますが、ごく少量のスペースしか必要ありません。その反対に、太い尾の履歴データは希にリクエストされます。複数のディスクが利用可能な場合、「ホット」データは高速ディスク(例えば、NVMe SSDまたはメモリ内)に置かれ、「コールド」データは比較的遅いもの(例えば、HDD)に置かれる場合があります。
データパートはMergeTree
エンジンテーブルの最小可動単位です。1つのパーツに属するデータは1つのディスクに保存されます。データパーツは、ユーザー設定に応じてバックグラウンドでディスク間を移動したり、ALTERクエリによって移動したりできます。
Terms
- ディスク — ファイルシステムにマウントされたブロックデバイス。
- デフォルトディスク — pathサーバー設定で指定されたパスを格納するディスク。
- ボリューム — 同等のディスクの順序付けされたセット(JBODに似ています)。
- ストレージポリシー — ボリュームのセットとそれらの間でデータを移動するためのルール。
記述されたエンティティに付けられた名前は、システムテーブル[system.storage_policies](/operations/system-tables/storage_policies)
および[system.disks](/operations/system-tables/disks)
で見つけることができます。テーブルに構成されたストレージポリシーの1つを適用するには、MergeTree
エンジンファミリのテーブルのstorage_policy
設定を使用します。
Configuration
ディスク、ボリューム、およびストレージポリシーは、config.d
ディレクトリ内のファイルの中にある<storage_configuration>
タグ内に宣言する必要があります。
ディスクは、クエリのSETTINGS
セクションに宣言することもできます。これは、例えば、URLでホストされているディスクを一時的に接続するための便利です。詳細については動的ストレージを参照してください。
構成構造:
タグ:
<disk_name_N>
— ディスク名。すべてのディスクの名前は異なる必要があります。path
— サーバーがデータ(data
およびshadow
フォルダー)を保存するパスで、/
で終わる必要があります。keep_free_space_bytes
— 保存されるべきフリースペースの量。
ディスク定義の順序は重要ではありません。
ストレージポリシー構成マークアップ:
タグ:
policy_name_N
— ポリシー名。ポリシー名は一意である必要があります。volume_name_N
— ボリューム名。ボリューム名は一意である必要があります。disk
— ボリューム内のディスク。max_data_part_size_bytes
— ボリュームのどのディスクにも保存できるパーツの最大サイズ。マージされたパーツのサイズがmax_data_part_size_bytes
を超えると、そのパーツは次のボリュームに書き込まれます。この機能により、新しい小さなパーツをホット(SSD)ボリュームに保持し、大きなサイズに達したときにコールド(HDD)ボリュームに移動できます。この設定は、ポリシーに1つのボリュームだけがある場合は使用しないでください。move_factor
— 利用可能なスペースがこのファクターより少なくなると、データは自動的に次のボリュームに移動し始めます(デフォルトは0.1)。ClickHouseは、現存するパーツをサイズが大きいものから小さいものへと降順に並べ、move_factor
条件を満たすために十分なサイズのパーツを選択します。すべてのパーツの合計サイズが不十分な場合は、すべてのパーツが移動されます。perform_ttl_move_on_insert
— データパートINSERT時のTTL移動を無効にします。デフォルト(有効な場合)の状態では、TTL移動ルールによりすでに期限切れのデータパートを挿入すると、そのパーツは直ちに移動ルールに宣言されたボリューム/ディスクに移動されます。これは、宛先ボリューム/ディスクが遅い場合(例:S3)には挿入を大幅に遅くする可能性があります。無効にした場合は、期限切れのデータパートがデフォルトボリュームに書き込まれ、その後すぐにTTLボリュームに移動されます。load_balancing
- ディスクバランスのポリシー、round_robin
またはleast_used
。least_used_ttl_ms
- すべてのディスクで更新可能なスペースを更新するためのタイムアウト(ミリ秒)(0
- 常に更新,-1
- 更新しない, デフォルトは60000
)。注意、ディスクがClickHouseのみに使用可能で、オンラインファイルシステムのリサイズ/縮小の影響を受けない場合は、-1
を使用してもよいですが、そうでない場合は推奨されません。最終的には、不正確なスペース配分につながるためです。prefer_not_to_merge
— この設定は使用しないでください。ボリューム上のデータパーツのマージを無効にします(これは有害でパフォーマンスの低下につながります)。この設定が有効になっている状態では(使用しないでください)、このボリュームでデータのマージが許可されません(これは悪い結果をもたらします)。これにより(しかし、あなたはそれを必要としません)、ClickHouseが遅いディスクでどのように動作するかを制御できます(しかし、ClickHouseの方がよく知っていますので、この設定を使用しないでください)。volume_priority
— ボリュームが埋められる順序を定義します。低い値は高い優先度を示します。パラメータ値は自然数であり、1からNの範囲を一緒にカバーするべきです(最低の優先度)。- すべてのボリュームにタグが付けられている場合、それらは指定された順序で優先されます。
- 一部のボリュームにのみタグが付けられている場合、タグなしのボリュームは最低の優先度を持ち、定義された順序で優先されます。
- タグが付けられていない場合、優先度は構成で宣言された順序に応じて設定されます。
- 2つのボリュームは同じ優先度の値を持つことができません。
構成の例:
与えられた例では、hdd_in_order
ポリシーはラウンドロビンアプローチを実装します。このポリシーは1つのボリューム(single
)のみを定義し、データパーツはそのすべてのディスクに円環式で保存されます。このようなポリシーは、複数の類似のディスクがシステムにマウントされているが、RAIDが構成されていない場合には非常に有用です。各個々のディスクドライブは信頼性がなく、レプリケーション係数を3以上にしたい場合があります。
システム内にさまざまな種類のディスクが利用可能な場合、moving_from_ssd_to_hdd
ポリシーを代わりに使用できます。ボリュームhot
はSSDディスク(fast_ssd
)からなり、そこに保存できるパートの最大サイズは1GBです。1GBを超えるサイズのすべてのパーツは、HDDディスクdisk1
を含むcold
ボリュームに直接保存されます。また、ディスクfast_ssd
が80%以上充填されると、データはバックグラウンドプロセスによってdisk1
に転送されます。
ストレージポリシー内のボリュームの列挙順序は、少なくとも1つのボリュームに明示的なvolume_priority
パラメータがない場合に重要です。
ボリュームが過剰に満たされると、データは次のボリュームに移動されます。ディスクの列挙順序も重要です。データは順に保存されます。
テーブルを作成する際には、設定されたストレージポリシーの1つを適用できます:
default
ストレージポリシーは、<path>
で指定された1つのディスクのみを含むボリュームを使用することを意味します。
テーブル作成後にストレージポリシーを変更するには、[ALTER TABLE ... MODIFY SETTING]クエリを使用し、新しいポリシーにすべての古いディスクと同名のボリュームを含める必要があります。
データパーツのバックグラウンド移動を実行するスレッド数は、background_move_pool_size設定で変更できます。
Details
MergeTree
テーブルの場合、データはさまざまな方法でディスクに到達します:
- 挿入(
INSERT
クエリ)の結果として。 - バックグラウンドマージおよびミューテーション中。
- 別のレプリカからのダウンロード時。
- パーティションのフリーズ結果として、ALTER TABLE ... FREEZE PARTITION。
これらのケースは、ミューテーションやパーティションのフリーズを除き、パートは指定されたストレージポリシーに応じてボリュームおよびディスクに保存されます:
- 保存パート用に十分なディスクスペースがある最初のボリューム(定義の順序で)が選択されます(
unreserved_space > current_part_size
)および指定されたサイズのパーツを保存することが許可される(max_data_part_size_bytes > current_part_size
)。 - このボリューム内で、前回のデータのチャンクを格納するために使用されたディスクの次のディスクが選択され、パートサイズよりもフリースペースが多いディスク(
unreserved_space - keep_free_space_bytes > current_part_size
)が選択されます。
内部では、ミューテーションやパーティションのフリーズはハードリンクを利用します。異なるディスク間のハードリンクはサポートされていないため、そのような場合、結果のパーツは初期のものと同じディスクに保存されます。
バックグラウンドでは、ボリューム間での移動は、フリースペースの量(move_factor
パラメータ)に基づいて構成ファイルで宣言された順序に従います。
データは最後のボリュームから最初のボリュームに移動されることはありません。バックグラウンド移動を監視するために、システムテーブル[system.part_log](/operations/system-tables/part_log)
(フィールドtype = MOVE_PART
)および[system.parts](/operations/system-tables/parts.md)
(フィールドpath
およびdisk
)を使用できます。また、詳細情報はサーバーログで見つけることができます。
ユーザーは、ALTER TABLE ... MOVE PART|PARTITION ... TO VOLUME|DISK ...クエリを使用して、パートやパーティションを1つのボリュームから別のボリュームに強制的に移動させることができます。すべての背景操作に関する制限が考慮されます。このクエリは、自身で移動を開始し、バックグラウンド操作の完了を待機しません。無料スペースが不十分な場合や、必要条件が満たされていない場合、ユーザーはエラーメッセージを受け取ります。
データの移動はデータレプリケーションに干渉しません。したがって、同じテーブルに対して異なるストレージポリシーを異なるレプリカに指定できます。
バックグラウンドマージとミューテーションが完了した後、古いパーツは一定の期間(old_parts_lifetime
)の後にのみ削除されます。
この期間中、他のボリュームやディスクには移動されません。したがって、パーツが最終的に削除されるまで、そのサイズは占有スペースの評価に考慮されます。
ユーザーは、JBODボリュームの異なるディスクに新しい大きなパーツを均等に割り当てることができます。これは、min_bytes_to_rebalance_partition_over_jbod設定を使用して実現します。
外部ストレージを使用したデータストレージ
MergeTree ファミリーのテーブルエンジンは、S3
、AzureBlobStorage
、HDFS
にデータを保存することができ、タイプ s3
、azure_blob_storage
、hdfs
に応じてディスクを使用します。詳細については、外部ストレージオプションの構成を参照してください。
外部ストレージとしての S3 の例で、ディスクタイプは s3
です。
設定マークアップ:
また、外部ストレージオプションの構成も参照してください。
ClickHouse バージョン 22.3 から 22.7 までは異なるキャッシュ設定が使用されているため、これらのバージョンを使用している場合は、ローカルキャッシュの使用を参照してください。
バーチャルカラム
_part
— パートの名前。_part_index
— クエリ結果におけるパートの順次インデックス。_part_starting_offset
— クエリ結果におけるパートの累積開始行。_part_offset
— パート内の行番号。_partition_id
— パーティションの名前。_part_uuid
— 一意のパート識別子 (MergeTree 設定assign_part_uuids
が有効な場合)。_part_data_version
— パートのデータバージョン (最小ブロック番号またはミューテーションバージョン)。_partition_value
—partition by
式の値 (タプル)。_sample_factor
— サンプルファクター (クエリから)。_block_number
— 行のブロック番号。allow_experimental_block_number_column
が true に設定されると、マージ時に永続化されます。
カラム統計
統計の宣言は、*MergeTree*
ファミリーのテーブルの CREATE
クエリのカラムセクションにあり、set allow_experimental_statistics = 1
を有効にしています。
統計は ALTER
ステートメントを使用しても操作できます。
これらの軽量統計は、カラム内の値の分布に関する情報を集約します。統計はすべてのパートに保存され、各挿入のたびに更新されます。
これらは、set allow_statistics_optimize = 1
を有効にする場合にのみ、prewhere 最適化に使用できます。
利用可能なカラム統計のタイプ
-
MinMax
数値カラムの範囲フィルタの選択性を推定可能にする列の最小値と最大値。
構文:
minmax
-
TDigest
数値カラムの近似パーセンタイル (例: 90 パーセンタイル) を計算するのに役立つ TDigest スケッチ。
構文:
tdigest
-
Uniq
列が含む一意の値の数を推定する HyperLogLog スケッチ。
構文:
uniq
-
CountMin
列内の各値の頻度の近似カウントを提供する CountMin スケッチ。
構文:
countmin
サポートされているデータ型
(U)Int*, Float*, Decimal(), Date, Boolean, Enum* | String または FixedString | |
---|---|---|
CountMin | ✔ | ✔ |
MinMax | ✔ | ✗ |
TDigest | ✔ | ✗ |
Uniq | ✔ | ✔ |
サポートされている操作
等価フィルタ (==) | 範囲フィルタ (>, >=, <, <= ) | |
---|---|---|
CountMin | ✔ | ✗ |
MinMax | ✗ | ✔ |
TDigest | ✗ | ✔ |
Uniq | ✔ | ✗ |
カラムレベルの設定
特定の MergeTree 設定は、カラムレベルでオーバーライドできます:
max_compress_block_size
— テーブルに書き込む前に圧縮される未圧縮データの最大ブロックサイズ。min_compress_block_size
— 次のマークを書き込む際に圧縮のために必要な未圧縮データの最小ブロックサイズ。
例:
カラムレベルの設定は、ALTER MODIFY COLUMN を使用して変更または削除できます。例えば:
- カラム宣言から
SETTINGS
を削除:
- 設定を変更:
- 1つまたは複数の設定をリセットし、同時にテーブルの CREATE クエリのカラム式から設定宣言を削除します。