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

MergeTree

MergeTreeエンジンおよびMergeTreeファミリーの他のエンジン(例:ReplacingMergeTreeAggregatingMergeTree)は、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が有効になっている場合、CREATE TABLEステートメントにORDER BY tuple()が暗黙的に追加されます。主キーの選択についてはSelecting a Primary Keyを参照してください。

PARTITION BY

PARTITION BYパーティショニングキー。オプション。ほとんどのケースではパーティションキーは必要なく、パーティション化が必要な場合でも、通常は月単位のパーティションキーより細かい粒度は必要ありません。パーティショニングはクエリを速くするものではありません(ORDER BY式とは対照的)。あまり細かいパーティショニングは使用しないでください。クライアントの識別子や名前でデータをパーティション化しないでください(代わりに、ORDER BY式の最初のカラムにクライアントの識別子や名前を設定してください)。

月ごとにパーティション化するには、toYYYYMM(date_column)式を使用します。ここで、date_columnDateタイプの日時を持つカラムです。ここでのパーティション名は"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

MergeTreeの設定を参照してください。

セクション設定の例

この例では、月ごとのパーティショニングを設定しています。

また、サンプリングのための式をユーザーIDのハッシュとして設定しています。これにより、各CounterIDEventDateに対してテーブルのデータを擬似ランダム化できます。データを選択するときにSAMPLE句を定義すると、ClickHouseはユーザーのサブセットに対して均等に擬似ランダムなデータサンプルを返します。

index_granularity設定は、8192がデフォルト値なので省略できます。

テーブルを作成するための廃止された方法
注記

新しいプロジェクトではこの方法を使用しないでください。可能であれば、古いプロジェクトを上記の方法に切り替えてください。

MergeTree() パラメータ

  • date-columnDateタイプのカラムの名前。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_partmin_rows_for_wide_part 設定によって制御されます。データパーツ内のバイト数または行数が、対応する設定値未満の場合、パーツは Compact 形式で保存されます。それ以外の場合は Wide 形式で保存されます。これらの設定がいずれも設定されていない場合、データパーツは Wide 形式で保存されます。

各データパーツは論理的にグラニュールに分けられます。グラニュールは、ClickHouse がデータを選択する際に読み取る最小の不可分のデータセットです。ClickHouse は行や値を分割しないため、各グラニュールは常に整数の行数を含みます。グラニュールの最初の行は、その行の主キーの値でマークされます。ClickHouse は各データパーツのためにマークを保存するインデックスファイルを生成します。主キーに含まれるかどうかに関係なく、各カラムに対しても同じマークが保存されます。これらのマークを使用すると、列ファイル内のデータを直接見つけることができます。

グラニュールのサイズは、テーブルエンジンの index_granularityindex_granularity_bytes 設定によって制限されています。グラニュール内の行数は [1, index_granularity] の範囲内にあり、行のサイズによって異なります。行のサイズが設定値を超える場合、グラニュールのサイズは行のサイズになります。

クエリにおける主キーとインデックス

(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設定を有効にします。 ORDER BY 句における NULL 値に対しては、NULLS_LASTの原則が適用されます。

主キーの選択

主キーのカラム数には明示的な制限はありません。データ構造に応じて、主キーに多くのカラムを含めることができます。これにより:

  • インデックスのパフォーマンスが向上します。

    主キーが(a, b)の場合、別のカラムcを追加すると、以下の条件が満たされていれば、パフォーマンスが向上します:

    • カラムcに対する条件を持つクエリがある。
    • (a, b)の値が同一の長いデータ範囲(index_granularityの数倍長い)の存在が一般的です。言い換えれば、別のカラムを追加することでかなり長いデータ範囲をスキップできる場合です。
  • データ圧縮を改善します。

    ClickHouseはデータを主キーでソートするため、一貫性が高いほど圧縮が良好になります。

  • CollapsingMergeTreeおよびSummingMergeTreeエンジンでデータパーツをマージする際の追加ロジックを提供します。

    この場合、主キーとは異なるソートキーを指定することが理にかなっています。

長い主キーは挿入パフォーマンスやメモリ消費に悪影響を与えますが、主キー内の追加のカラムはClickHouseのSELECTクエリのパフォーマンスには影響しません。

ORDER BY tuple()構文を使用して主キーなしでテーブルを作成できます。この場合、ClickHouseは挿入時の順序でデータを保存します。INSERT ... SELECTクエリによってデータを挿入する際にデータの順序を保存したい場合は、max_insert_threads = 1を設定してください。

最初の順序でデータを選択するには、シングルスレッド SELECT クエリを使用します。

ソートキーとは異なる主キーの選択

主キー(インデックスファイルに各マークのために書き込まれる値の式)をソートキー(データパーツ内の行をソートするための式)とは異なるものとして指定することができます。この場合、主キーの式タプルはソートキーの式タプルの接頭辞でなければなりません。

この機能は、SummingMergeTreeおよび AggregatingMergeTreeテーブルエンジンを使用する際に便利です。これらのエンジンを使用する一般的なケースでは、テーブルには「次元」と「測定値」という2種類のカラムが存在します。典型的なクエリは、任意の GROUP BY で測定値カラムの値を集約し、次元でフィルタリングします。SummingMergeTreeとAggregatingMergeTreeはソートキー値が同じ行を集約するため、すべての次元をソートキーに加えることが自然です。その結果、キー式は長いカラムのリストで構成され、このリストは新たに追加された次元で頻繁に更新される必要があります。

この場合、効率的な範囲スキャンを提供するために主キーに数カラムだけを残し、残りの次元カラムをソートキーのタプルに追加することが理にかなっています。

ソートキーのALTERは軽量な操作です。なぜなら、新しいカラムがテーブルとソートキーの両方に同時に追加されるとき、既存のデータパーツは変更の必要がないからです。古いソートキーが新しいソートキーの接頭辞であり、新しく追加されたカラムにデータがない場合、テーブルの変更時にデータは古いソートキーと新しいソートキーの両方に基づいてソートされます。

クエリにおけるインデックスとパーティションの使用

SELECT クエリの場合、ClickHouseはインデックスが使用できるかどうかを分析します。インデックスは、WHERE / PREWHERE 句に、主キーまたはパーティショニングキーにあるカラムや式に対する等号または不等号の比較演算を示す式、または特定の部分的に繰り返されるこれらのカラムの関数の論理関係が含まれている場合に使用できます。

したがって、主キーの1つまたは複数の範囲に対して迅速にクエリを実行できます。この例では、特定のトラッキングタグ、特定のタグおよび日付範囲、特定のタグおよび日付、複数のタグと日付範囲などに対してクエリを実行するとすばやくなります。

次のように設定されたエンジンを考えてみましょう。

この場合、クエリでは:

ClickHouseは、誤ったデータを剪定するために主キーインデックスを使用し、誤った日付範囲にあるパーティションを剪定するために月ごとのパーティショニングキーを使用します。

上記のクエリは、複雑な式に対してもインデックスが使用されることを示しています。テーブルからの読み取りは、インデックスを使用してもフルスキャンより遅くならないように整理されています。

以下の例では、インデックスが使用できません。

クエリを実行する際にClickHouseがインデックスを使用できるかどうかを確認するには、設定 force_index_by_date および force_primary_key を使用します。

月ごとのパーティショニングキーは、適切な範囲の日付を含むデータブロックのみを読むことを可能にします。この場合、データブロックには多くの日付のデータ(最大で1ヶ月分)が含まれる可能性があります。ブロック内では、データは主キーによってソートされています。なお、主キーに日付が最初のカラムとして含まれていない場合があります。このため、主キーのプレフィックスを指定せずに日付条件のみのクエリを使用すると、単一の日付のデータよりも多くのデータが読み込まれる場合があります。

部分的単調増加主キーに対するインデックスの使用

例えば、月の日を考えてみましょう。これらは、1ヶ月の間に単調増加したシーケンスを形成しますが、より長い期間では単調増加しません。これは部分的に単調なシーケンスです。ユーザーが部分的な単調主キーを持つテーブルを作成した場合、ClickHouseは通常通りスパースインデックスを作成します。ユーザーがこの種のテーブルからデータを選択するとき、ClickHouseはクエリ条件を分析します。ユーザーがインデックスの2つのマークの間のデータを取得したい場合、これらのマークが1ヶ月内に収まる場合、ClickHouseはこの特定の場合にインデックスを使用できます。なぜなら、クエリのパラメータとインデックスのマークの間の距離を計算できるからです。

クエリパラメータ範囲内の主キーの値が単調増加したシーケンスを表さない場合、ClickHouseはインデックスを使用できません。この場合、ClickHouseはフルスキャン方式を使用します。

ClickHouseは、月の日シーケンスだけでなく、部分的に単調増加したシーケンスを表す任意の主キーにもこの論理を適用します。

データスキッピングインデックス

インデックス宣言は、CREATEクエリのカラムセクションに含まれます。

*MergeTreeファミリーのテーブルでは、データスキッピングインデックスを指定できます。

これらのインデックスは、指定された式に関する情報を、granularity_valueのグラニュールからなるブロックで集約します(グラニュールのサイズは、テーブルエンジンのindex_granularity設定で指定されます)。その後、これらの集約は、SELECTクエリにおいて、whereクエリが満たされない大きなデータブロックをスキップするために、ディスクから読み取るデータ量を削減するために使用されます。

GRANULARITY句は省略可能であり、granularity_valueのデフォルト値は1です。

上記の例のインデックスは、次のクエリにおいてClickHouseによってディスクから読み取るデータ量を減らすために使用できます:

データスキッピングインデックスは、複合カラムに対しても作成できます:

利用可能なインデックスの種類

MinMax

指定された式の極値を保存します(式がtupleの場合、各要素の極値を保存します)。主キーと同様に、データブロックをスキップするために保存された情報を使用します。

構文:minmax

Set

指定された式のユニークな値を保存します(最大でmax_rows行、max_rows=0は「制限なし」を意味します)。ブロック上でWHERE式が満たされないかどうかを確認するためにこの値を使用します。

構文:set(max_rows)

Bloom Filter

指定されたカラム用のブルームフィルターを保存します。オプションのfalse_positiveパラメータは、0と1の間の値を持ち、フィルターからの偽陽性応答を受け取る確率を指定します。デフォルト値は0.025です。サポートされるデータタイプ:Int*UInt*Float*EnumDateDateTimeStringFixedStringArrayLowCardinalityNullableUUIDMapMapデータ型については、クライアントはインデックスをキーワードまたは値に対して作成するかどうかを、mapKeysまたはmapValues関数を使用して指定できます。

構文:bloom_filter([false_positive])

N-gram Bloom Filter

指定されたデータブロックのすべてのn-gramを含むブルームフィルターを保存します。データ型:StringFixedStringMapのみに対応しています。EQUALSLIKEIN式の最適化に使用できます。

構文:ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)

  • n — ngramサイズ、
  • size_of_bloom_filter_in_bytes — ブルームフィルターのサイズ(ここでは大きな値を使用できます。例えば256または512。なぜなら、圧縮が良好だからです)。
  • number_of_hash_functions — ブルームフィルターで使用されるハッシュ関数の数。
  • random_seed — ブルームフィルターハッシュ関数のシード。

ユーザーは、ngrambf_v1のパラメータセットを推定するためにUDFを作成できます。クエリステートメントは次のとおりです。

これらの関数を使用するには、少なくとも二つのパラメータを指定する必要があります。例えば、グラニュールに4300のn-gramがあり、偽陽性を0.0001未満に抑えたい場合、他のパラメータは次のクエリを実行することで推定できます:

もちろん、他の条件によってパラメータを推定するためにこれらの関数も使用可能です。 これらの関数に関する内容は、こちらを参照してください。

Token Bloom Filter

ngrambf_v1と同じですが、n-gramの代わりにトークンを保存します。トークンは非英数字文字で区切られたシーケンスです。

構文:tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)

特定用途

  • おおよその最近接隣接検索をサポートするための実験的インデックス。詳細についてはこちらを参照してください。
  • フルテキスト検索をサポートするための実験的フルテキストインデックス。詳細についてはこちらを参照してください。

関数のサポート

WHERE句の条件には、カラムを操作する関数の呼び出しが含まれています。カラムがインデックスの一部である場合、ClickHouseは関数を実行する際にこのインデックスを使用しようとします。ClickHouseはインデックスを使用するための異なる関数のサブセットをサポートしています。

set型のインデックスはすべての関数で利用可能です。他のインデックスタイプは次のようにサポートされています。

関数 (演算子) / インデックス主キーminmaxngrambf_v1tokenbf_v1bloom_filterfull_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)のようにします。

注記

Bloomフィルターは誤検出を発生させることがあるため、ngrambf_v1tokenbf_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')

プロジェクション

プロジェクションは、マテリアライズドビューのようなもので、部分レベルで定義されます。クエリでの自動使用と整合性の保証を提供します。

注記

プロジェクションを実装する際は、force_optimize_projection設定についても考慮する必要があります。

プロジェクションは、FINAL修飾子を伴ったSELECT文ではサポートされていません。

プロジェクションクエリ

プロジェクションクエリは、プロジェクションを定義するものです。これは、親テーブルからデータを暗黙的に選択します。

構文

プロジェクションは、ALTER文を使用して修正または削除できます。

プロジェクションストレージ

プロジェクションは、部分ディレクトリ内に保存されます。それはインデックスに似ていますが、匿名のMergeTreeテーブルの部分を保存するサブディレクトリが含まれています。テーブルは、プロジェクションの定義クエリによって誘発されます。GROUP BY句がある場合、基盤のストレージエンジンはAggregatingMergeTreeとなり、すべての集計関数はAggregateFunctionに変換されます。ORDER BY句がある場合、MergeTreeテーブルはそれを主キー式として使用します。マージプロセス中にプロジェクション部分は、そのストレージのマージルーチンを介してマージされます。親テーブルの部分のチェックサムは、プロジェクションの部分と組み合わされます。他のメンテナンス作業は、スキップインデックスに似ています。

クエリ分析

  1. プロジェクションが、ベーステーブルをクエリする場合と同じ結果を生成するかを確認します。
  2. 読み取るグラニュールが最も少ない最適な一致を選択します。
  3. プロジェクションを使用するクエリパイプラインは、元の部分を使用するものとは異なります。プロジェクションが一部の部分に存在しない場合、パイプラインを追加して「動的に」投影することができます。

同時データアクセス

同時テーブルアクセスのために、マルチバージョンを使用します。言い換えれば、テーブルが同時に読み取られ、更新されるとき、データはクエリの時点で現在の部分のセットから読み取られます。長時間ロックはありません。挿入は読み取り操作の妨げにはなりません。

テーブルからの読み取りは自動的に並列化されます。

カラムおよびテーブルのTTL

値のライフタイムを決定します。

TTL句は、テーブル全体および各個別カラムに対して設定できます。テーブルレベルのTTLは、ディスクやボリューム間でデータを自動的に移動させるロジックや、すべてのデータが期限切れになったパーツを再圧縮するロジックを指定することもできます。

式は、DateまたはDateTimeデータ型に評価される必要があります。

構文

カラムのライフタイムを設定するには:

intervalを定義するには、時間間隔演算子を使用します。たとえば:

カラムTTL

カラムの値が期限切れになると、ClickHouseはそれらをカラムデータタイプのデフォルト値に置き換えます。データ部分内のすべてのカラム値が期限切れになると、ClickHouseはこのカラムをファイルシステムのデータ部分から削除します。

TTL句はキーカラムには使用できません。

TTL付きのテーブルを作成する:

既存テーブルのカラムにTTLを追加する

カラムのTTLを変更する

テーブル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には偶発的な値が含まれます。

期限切れデータの削除

期限切れのTTLを持つデータは、ClickHouseがデータパーツをマージする際に削除されます。

ClickHouseがデータが期限切れであることを検出すると、オフスケジュールのマージを実行します。このようなマージの頻度を制御するために、merge_with_ttl_timeoutを設定できます。値が低すぎると、多くのオフスケジュールのマージが行われ、リソースを大量に消費する可能性があります。

マージの間にSELECTクエリを実行すると、期限切れデータを取得する可能性があります。これを回避するには、SELECTの前にOPTIMIZEクエリを使用してください。

関連情報

ディスクタイプ

ローカルブロックデバイスに加えて、ClickHouseはこれらのストレージタイプをサポートしています:

データストレージに複数のブロックデバイスを使用する

はじめに

MergeTreeファミリーのテーブルエンジンは、複数のブロックデバイスにデータを保存できます。たとえば、特定のテーブルのデータが暗黙的に「ホット」と「コールド」に分割される場合に便利です。最新のデータは定期的に要求されますが、必要とされるスペースはわずかです。逆に、太い尾を持つ履歴データはめったに要求されません。複数のディスクが利用可能な場合、「ホット」データを高速ディスク(たとえば、NVMe SSDやメモリ内)に、その一方で「コールド」データを比較的遅いディスク(たとえば、HDD)に置くことができます。

データ部分は、MergeTreeエンジンテーブルの最低移動単位です。一つのパーツに属するデータは一つのディスクに保存されます。データ部分は、ユーザー設定に従って、バックグラウンドでディスク間で移動されることも、ALTERクエリを利用して移動されることもできます。

用語

  • ディスク — ファイルシステムにマウントされたブロックデバイス。
  • デフォルトディスク — pathサーバー設定に指定したパスを保存するディスク。
  • ボリューム — 同等のディスクの順序付けられたセット(JBODに似ています)。
  • ストレージポリシー — ボリュームのセットとそれらの間でデータを移動するルール。

説明されたエンティティに与えられた名前は、システムテーブルのsystem.storage_policiessystem.disksに見つけることができます。テーブルに設定されているストレージポリシーの1つを適用するには、MergeTreeエンジンファミリのテーブルのstorage_policy設定を使用します。

構成

ディスク、ボリューム、ストレージポリシーは、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ポリシーがラウンドロビンアプローチを実装しています。このポリシーは唯一のボリューム(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つのディスクで構成された1つのボリュームのみを使用することを意味します。テーブル作成後にストレージポリシーを変更することができます。新しいポリシーには、同じ名前の古いディスクとボリュームをすべて含む必要があります。

データ部分のバックグラウンド移動を実行するスレッド数は、background_move_pool_size設定によって変更できます。

詳細

MergeTreeテーブルの場合、データは次の方法でディスクに到達します:

これらのケースと異なり、ミューテーションやパーティションフリーズの場合、部分は指定されたストレージポリシーに基づいてボリュームとディスクに保存されます:

  1. 部分を格納するための十分なディスクスペースを持ち、指定されたサイズの部分を保存することを許可する(unreserved_space > current_part_size および max_data_part_size_bytes > current_part_size)最初のボリューム(定義の順番)を選択します。
  2. このボリューム内では、前のデータチャンクを保存するために使用されたディスクの次に選択し、そのディスクの空き容量が部分サイズよりも大きいディスクを選択します(unreserved_space - keep_free_space_bytes > current_part_size)。

基礎的な部分、ミューテーションおよびパーティションフリーズは、ハードリンクを使用します。異なるディスク間のハードリンクはサポートされていないため、このような場合、結果の部分は元のものと同じディスクに保存されます。

バックグラウンドでは、ボリューム間で自由な空間に基づいてデータが移動されます(move_factorパラメータに基づいて)、また構成ファイルで宣言された順序に従います。データは、最後のボリュームから最初のボリュームに移動しません。システムテーブルのsystem.part_logtype = MOVE_PARTフィールド)やsystem.partspathおよびdiskフィールド)を使用してバックグラウンド移動を監視できます。さらに、詳細情報はサーバーログで見つかります。

ユーザーは、ALTER TABLE ... MOVE PART|PARTITION ... TO VOLUME|DISK ...クエリを使用して、部分またはパーティションを1つのボリュームから別のボリュームに強制的に移動することができます。この操作では、バックグラウンド操作に対するすべての制約が考慮されます。クエリは独自に移動を開始し、バックグラウンド操作の完了を待ちません。十分な空きスペースがない場合や必要な条件が満たされていない場合、ユーザーはエラーメッセージを受け取ります。

データを移動することは、データのレプリケーションに干渉しません。したがって、同じテーブルに対して異なるレプリカに異なるストレージポリシーを指定できます。

バックグラウンドマージとミューテーションが完了した後、古い部分は特定の時間(old_parts_lifetime)が経過するまで削除されません。 この時間の間、古い部分は他のボリュームやディスクに移動されません。したがって、部分が最終的に削除されるまで、占有されているディスクスペースの評価にカウントされます。

ユーザーは、JBODボリュームの異なるディスクに新しい大きな部分をバランスよく割り当てるために、min_bytes_to_rebalance_partition_over_jbod設定を使用できます。

外部ストレージを使用したデータストレージ

MergeTree ファミリーのテーブルエンジンは、s3azure_blob_storagehdfs タイプのディスクを使用して、データを S3AzureBlobStorageHDFS に保存できます。詳細については、外部ストレージオプションの構成を参照してください。

S3 を外部ストレージとして使用する例です。ディスクのタイプは s3 になります。

構成マークアップ:

また、外部ストレージオプションの構成もご覧ください。

キャッシュ構成

ClickHouse バージョン 22.3 から 22.7 は異なるキャッシュ構成を使用しているため、これらのバージョンを使用している場合は ローカルキャッシュの使用を参照してください。

仮想カラム

  • _part — パーツの名前。
  • _part_index — クエリ結果におけるパーツの連続インデックス。
  • _partition_id — パーティションの名前。
  • _part_uuid — ユニークなパート識別子(MergeTree 設定 assign_part_uuids が有効な場合)。
  • _partition_valuepartition by 式の値(タプル)。
  • _sample_factor — サンプル係数(クエリから)。
  • _block_number — 行のブロック番号で、allow_experimental_block_number_column が true に設定されている場合、マージ時に永続化されます。

カラム統計

Experimental feature. Learn more.
Not supported in ClickHouse Cloud

統計の宣言は、*MergeTree* ファミリーのテーブルの CREATE クエリのカラムセクションにあり、set allow_experimental_statistics = 1 を有効にする必要があります。

ALTER ステートメントを使用して統計を操作することもできます。

これらの軽量統計は、カラム内の値の分布に関する情報を集約します。統計はすべてのパートに格納され、挿入が行われるたびに更新されます。
それらは、set allow_statistics_optimize = 1 を有効にする場合のみ、prewhere の最適化に使用できます。

利用可能なカラム統計のタイプ

  • MinMax

    最小値と最大値のカラムの値で、数値カラムに対する範囲フィルターの選択性を推定するのに役立ちます。

    構文: minmax

  • TDigest

    TDigest スケッチは、数値カラムの近似パーセンタイル(例えば、90パーセンタイル)を計算できます。

    構文: 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 クエリのカラム式の設定命令も削除します。