ClickHouseのドキュメントを雑に翻訳してみた(Table engines)

以下、 https://clickhouse.yandex/docs/en/table_engines/ の雑な翻訳。Google翻訳に頼りっきりなので品質は期待しないでください。(でも、誤訳などのフィードバックは歓迎)

文章中の (?) 部分は **特に** 翻訳が怪しいものになります。(~~元の英文も一部読みにくい~~) あと、全部訳していません。

# Table engines

ClickHouseのテーブルエンジン(テーブルのタイプ)は、次の事を決定します。

* データの格納方法と場所、データの書き込む場所、読み込む場所
* サポートされているクエリーや機能
* 同時データアクセス
* Indexの有無
* マルチスレッドの実行が可能かどうか
* レプリケーション
* データを読み取るとき、テーブルエンジンは必要な列のセットのみ抽出する必要があります。ただし、クエリがテーブルエンジン内で部分的に処理される事があります。

最も重要なタスクの場合、MergeTreeファミリーのエンジンを使用する必要があります。

## TinyLog

(省略)

## Log

(省略)

## Memory

(省略)

## MergeTree

MergeTreeエンジンは、プライマリーキーと日付によるインデックスをサポートし、リアルタイムでデータにデータ更新を可能にします。MergeTreeエンジンは、ClickHouseで最も高度なテーブルエンジンです。 [Merge](#merge) エンジンとは混同しないでください。

MergeTreeエンジンでのテーブル作成では、日付を含むData型の列の名前、サンプリング式(オプション)、表の主キーを定義するタプル、及び検索粒度のパラメータを受け付けます。

例:

```
MergeTree(EventDate, (CounterID, EventDate), 8192)
```

例(サンプリング式付き):

```
MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
```

MergeTree型テーブルには、Date型のカラムが必須です。 例えば `EventDate` カラムなど。また、DateTime型ではなくDate型でなければなりません。

主キーは、任意の式からなるタプル(通常これはカラムのタプル)または、単一の式になります。

オプションのサンプリング式には、任意の式を使用できます。主キーとして存在する必要があります。上記の例では `UserID` のハッシュを使用して、各 `CounterID` および `EventDate` の表にデータを擬似ランダムに分散しています。(?) 言い換えれば、問い合わせでSAMPLE句を使用すると、ユーザーのサブセットのデータを均等に擬似ランダムサンプリングします。
テーブルは一連のパーツとして実装されています。各パーツは主キーによってソートされます。さらに、各パーツには、最小及び最大日付が割り当てられています。テーブルにデータを挿入すると、新しくソートされたパーツが作成されます。(パーツの)マージプロセスは、バックグラウンドで定期的に実行されます。マージするときは、いくつかのパーツが選択され(通常は最小のも)、元の大きなソートされたパーツにマージされます。

つまり、テーブルへの挿入時、増分ソートが行われます。マージ作業は常に小さい順にソートされ、マージ作業自体、多くの作業(時間)を要しないように実装されています。

INSERT中、異なる月に属するデータは、異なるパーツに分割されます。異なる月のパーツ同士は決して統合されません。これの目的は、バックアップの容易なローカルデータを提供するためです。

パーツは特定の閾値のサイズまで結合され、長すぎるサイズのマージはありません。

各パーツについて、インデックスファイルも書き込まれます。インデックスファイルには、テーブル無い全ての `index_granularity` 行の主キー値が含まれています。つまり、これはソートデータの省略されたインデックスです。

カラムについては、各 `index_granularity` 行に `marks` が書き込まれ、特定の範囲でデータを読み取る事が出来ます。

テーブルから読み込むとき、SELECTクエリーはインデックスを使用できるか解析します。 `WHERE` または `PREWHERE` 句に、等価比較または非等価比較演算を表す式(ひとつの結合要素または、`entirely`(?))がある場合、または主キーか日付のカラム上に `IN` がある場合、ブール演算子を使用している場合、インデックスを使用できます。

従って、ひとつまたは複数のプライマリーキーを含んだクエリは素早く実行できます。上記の例では、特定のカウンターと日付の範囲、特定のカウンターと日付、複数のカウンターと日付範囲等のクエリが素早く実行されます。

```
SELECT count() FROM table WHERE EventDate = toDate(now()) AND CounterID = 34
SELECT count() FROM table WHERE EventDate = toDate(now()) AND (CounterID = 34 OR CounterID = 42)
SELECT count() FROM table WHERE ((EventDate >= toDate('2014-01-01') \
 AND EventDate <= toDate('2014-01-31')) OR EventDate = toDate('2014-05-01'))\
 AND CounterID IN (101500, 731962, 160656)\
 AND (CounterID = 101500 OR EventDate != toDate('2014-05-01'))
```

これら全てのケースで、日付と主キーによってインデックスが使用されます。インデックスは複雑な式でも使用できます。テーブルからの読み取りは、インデックスの仕様がフルスキャンよりも遅くならないように更新されています。

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

```
SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%'
```

ClickHouseがクエリの実行時に、インデックスを使用できるかどうか確認するには、
 `force_index_by_dateandforce_primary_key` という設定を使用します。

日付によるインデックスでは、日付を含む部分のみを目的の範囲から読み取る事が出来ます。ただし、データパーツには多くの日付(1ヶ月全体)のデータが含まれている場合がありますが、1つのパーツでは主キーによってデータが順序づけられています。このため、プライマリーキーのプレフィックスを指定していない日付の条件のみのクエリを使用すると、単一の日付の条件よりも多くのデータ読み込みが発生します。

並列テーブルへのアクセスでは、マルチバージョニングを使用します。言い換えると、テーブルが同時に読み込まれ、更新されると、クエリの発行時点であるパーツのセットからデータが読み出されます。長い(テーブル)ロックはありません。データの挿入は、読み取り操作の最中に発生しません。

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

`OPTIMIZE` クエリはサポートされ、追加のマージステップと呼ばれます。

単一の大きなテーブルを使用し、小さなチャンクでデータを継続的に追加できます。これがMergeTreeの目的です。

データのレブリケーションは、MergeTreeファミリー全てのテーブルで可能です。(詳しくは [Data replication](#data-replication) 参照)

(参考資料: [ClickHouse のパーティション](https://qiita.com/mikage/items/23da072340843a6c24e9))

## Custom partitioning key

バージョン `1.1.54310` より、MergeTreeファミリーのテーブルを任意のパーティションで作成することが出来ます。(つまり月単位のパーティション以外を作成可能)

パーティションキーは、テーブルカラムの式、タプルの式(プライマリーキーに似ています)です。パーティションキーは省略できます。テーブルを作成するとき、 `ENGINE` の説明に新しい構文でパーティションキーを指定します。

```
ENGINE [=] Name(...) [PARTITION BY expr] [ORDER BY expr] [SAMPLE BY expr] [SETTINGS name=value, ...]
```

MergeTreeテーブルの場合、パーティション式は `PARTITION BY` のあとに指定し、 `ORDER BY` のあとにプライマリーキー、 `SAMPLE BY` のあとにサンプリングキー、及び `SETTINGS` は他の設定と同様に、 `index_granularity` (オプション、デフォルト値は `8192`)、他 [`MergeTreeSettings.h`](https://github.com/yandex/ClickHouse/blob/master/dbms/src/Storages/MergeTree/MergeTreeSettings.h) から他の設定も行えます。他のエンジンパラメータは、従来通りエンジン名のあと括弧内に指定します。

例:

```
ENGINE = ReplicatedCollapsingMergeTree('/clickhouse/tables/name', 'replica1', Sign)
    PARTITION BY (toMonday(StartDate), EventType)
    ORDER BY (CounterID, StartDate, intHash32(UserID))
    SAMPLE BY intHash32(UserID)
```

従来の月別区分は、 `YYYYMM(date_column)` で表されます。

古いスタイルのテーブルをカスタムパーティションを持つテーブルに変換する事は出来ません。(SELECT,　INSERT を介してのみ)

このテーブルが作成されたあと、マージはパーティション式と同じ値を持つデータパーツに対してのみ働きます。注意:過度に細かいパーティション(約1,000個以上のパーティション)を作成しないでください。SELECTのパフォーマンスが低下します。

`ALTER PARTITION` コマンドでパーティションを指定するには、パーティション式(またはタプル)の値を指定します。定数と定数式をサポートします。

例:

```
ALTER TABLE table DROP PARTITION (toMonday(today()), 1)
```

上記の例では、現在の週のパーティションをドロップします。 `OPTIMIZE` クエリについても同様です。パーティション化されていないテーブルに唯一のパーティションを指定するには、 `PARTITION tuple()` を指定します。(?)

注意: 古いスタイルの表の場合、パーティション番号は `201710` または文字列 `'201710'` のいずれかで指定できます。新しいスタイルのテーブルの構文の型指定は厳密です(VALUES入力フォーマットはパーサーに似ています(?))更に、 `ALTER TABLE FREEZE PARTITION` は新しい形式の表に対して完全一致を使用する必要があります。(プリフィックスのマッチではありません)

`system.part` テーブルの `partition` カラムには、 `ALTER` クエリで使用するパーティション式の値を指定します。(クォータが削除されている場合)名前列には、新しいフォーマットでデータ部分の名前を指定します。

従来: `20140317_2040323_2_2_0` (最小日_最大日_最小ブロック番号_最大ブロック番号_レベル)

現在: `201403_2_2_0` (パーティションID_最小ブロック番号_最大ブロック番号_レベル)

パーティションIDは、ファイルシステムと [ZooKeeper](https://zookeeper.apache.org/) のデータパーツの名前に使用される文字列識別子です(可能であれば、人が読める形式)パーティションキーの代わりに `ALTER` クエリで指定できます。例: パーティションキー `toYYYYMM(EventDate)`; `ALTER` は `PARTITION 201710` または `PARTITION ID '201710'` を指定できます。

他の例: `00502_custom_partitioning_local, 00502_custom_partitioning_replicated_zookeeper`

## ReplacingMergeTree

このエンジンテーブルは MergeTree と異なり、同じプライマリキー値を持つ重複エントリを削除します。

テーブルエンジンの最後のオプションパラメータは、 `version` カラムです。マージすると、同じプライマリキー値を持つ全ての行が1行にまとめられます。 `version` カラムが指定されている場合は、最も新しいバージョンの行が残ります。それ以外の場合、最後の行を残します。

`version` カラムは、 UInt型 `(UInt8,UInt16,UInt32,UInt64)` 、Date型、DateTime型でなければなりません。

```
ReplacingMergeTree(EventDate, (OrderID, EventDate, BannerID, ...), 8192, ver)
```

データはマージ処理中にのみ重複排除されます。マージはある時間バックグラウンドで実行されるため、特定のタイミングでは重複は発生し得ます。 `OPTIMIZE` クエリを使用してスケジュールされてないマージを実行する事は出来ますが、大量のデータの読み書きが発生するため使用しないでください。

従って `ReplacingMergeTree` は、領域を節約するためにバックグラウンドで重複データを消去するのに適していますが、(特定タイミングで)重複がない事を保証するものではありません。

このエンジンは Yandex.Metrica では使用されていませんが、他の Yandex プロジェクトで適用されています。

### SummingMergeTree

このエンジンは、マージ中にデータの合計計算する点で、MergeTreeとは異なります。

```
SummingMergeTree(EventDate, (OrderID, EventDate, BannerID, ...), 8192)
```

合計計算するカラムは暗黙的です。マージするとき、同じプライマリーキーの値(この例では `OrderID, EventDate, BannerID,...`)を持つ全ての行は、プライマリーキーの一部ではない数値列に合計された値を持ちます。

```
SummingMergeTree(EventDate, (OrderID, EventDate, BannerID, ...), 8192, (Shows, Clicks, Cost, ...))
```

合計するカラムは明示的に設定されます。(上記例の最後のパラメータ、 `Shows, Click, Cost,...`) マージするとき、同じ主キーとを持つ全ての行の値は、指定されたカラムの合計を計算します。指定されたカラムは数値でなければならず、主キーの一部であってはなりません。

これらのカラムの全てで値が `NULL` だった場合、行は削除されます。(ただし、データ部分行がない場合は例外です。)

主キーの一部では無い他の行については、マージ時に最初に発生する値が選択されます。

読み取り操作では、集計は行われません。必要な場合は、適切な `GROUP BY` を記述します。

さらに、テーブルは特別な方法で処理されるネスとされたデータ構造を持つ事が出来ます。ネスとした表の名前が `Map` で終わり、次の基準を基準を満たすカラムを少なくとも2つ含む場合:

* 最初のテーブルは数値 `((U)IntN, Date, DateTime)` です。これをキーと呼びます。
* 他のカラムは算術 `((UIntN, FloatN)` です。これは `values...)` と呼ばれます。 次に、このネストしたテーブルは `key => (値)` のマッピングとして解釈され、その行をマージすると、2つのデータセットの要素は `values` の総和を `key` によってマージされます。(?)

例:

```
[(1, 100)] + [(2, 150)] -> [(1, 100), (2, 150)]
[(1, 100)] + [(1, 150)] -> [(1, 250)]
[(1, 100)] + [(1, 150), (2, 150)] -> [(1, 250), (2, 150)]
[(1, 100), (2, 150)] + [(1, -100)] -> [(2, 150)]
```

`Map` の集計には、関数 `sumMap(key,value)` を使用します。

ネストされたデータ構造の場合、列を合計するリストを指定する必要はありません。

このテーブルエンジンは特に有用ではありません。あらかじめ集計されたデータを保存すると、システムの利点の一部が失われる事に注意してください。

## AggregatingMergeTree

このエンジンは、MeregeTreeとはテーブルに格納された集合関数の状態を、同じ主キーの値を持つ行に対して結合する点が異なります。(?)

これを機能させるには、AggregateFunctionデータタイプと、集合関数の `-State`, `-Merge` 修飾子を使用します。もっと詳しく調べてみましょう。

AggregateFunctionデータ型があります。これはパラメトリックデータ型です。パラメータとして、集合関数の名前が渡され、次に引数の型が渡されます。

例:

```
CREATE TABLE t
(
    column1 AggregateFunction(uniq, UInt64),
    column2 AggregateFunction(anyIf, String, UInt8),
    column3 AggregateFunction(quantiles(0.5, 0.9), UInt64)
) ENGINE = ...
```

このタイプの列には、集合関数の状態が格納されます。

このタイプの値を取得するには、 `State` サフィックスとともに集合関数を使用します。

例: `uniqState(UserID), quantilesState(0.5,0.9)(SendTiming)`

対応する `uniq` および `quantiles` 関数とは対照的に、これらの関数は準備された値ではなく状態を返します。つまり、AggregateFunction型の値を返します。

AggregateFunction型の値はPretty形式では出力できません。他のフォーマットでは、これらのタイプの値は実装固有のバイナリデータとして出力されます。AggregateFunction型の値は、出力またはダンプでの保存を目的としたものではありません。

AggregateFunction型の値で行う事が出来る唯一の便利な事は、状態を結合して結果を得る事です。これは基本的に集合の終了を意味します。この目的のために、 `Merge` サフィックスを伴う集合関数が使用されます。例: `uniqMerge(UserIDState)` 。ここで、 `UserIDState` はAggregateFunctionタイプを持つ。

言い換えれば、 `Merge` サフィックスを持つ集合関数は状態の集合をとり、それらを結合し、結果を返します。例としては、これら2つのクエリは同じ結果を返します。

```
SELECT uniq(UserID) FROM table
SELECT uniqMerge(state) FROM (SELECT uniqState(UserID) AS state FROM table GROUP BY RegionID)
```

AggregationMergeTreeエンジンはマージ処理では、異なるテーブル行の集合関数の状態を同じ主キー値と組み合わを行います。

AggregateFunction値を明示的に定義する事は出来ないため、通常のINSERTを使用してAggregateFunction列を含む情報を挿入する事は出来ません。代わりに、State集合関数でINSERT SELECTを行います。

AggregatingMergeTreeテーブルでのSELECTは、 `GROUP BY` と集合関数を `-Merge` 修飾子とともに使用してデータ集約を完了させます。

インクリメンタル・データ・アグリゲーション、アグリゲーティド・マテリアライズド・ビューをAggregatingMergeTree テーブルを使用できます。(?)

例:

`test.visits` テーブルの情報から AggregatingMergeTree のマテリアライズビューテーブルを作成する:

```
CREATE MATERIALIZED VIEW test.basic
ENGINE = AggregatingMergeTree(StartDate, (CounterID, StartDate), 8192)
AS SELECT
    CounterID,
    StartDate,
    sumState(Sign)    AS Visits,
    uniqState(UserID) AS Users
FROM test.visits
GROUP BY CounterID, StartDate;
```

`test.visit` テーブルにデータを挿入する。データはビューテーブルに反映され、集合関数で計算される。

```
INSERT INTO test.vists ...
```

データの集計は `GROUP BY` を使って `SELECT` します。

```
SELECT
    StartDate,
    sumMerge(Visits) AS Visits,
    uniqMerge(Users) AS Users
FROM test.basic
GROUP BY StartDate
ORDER BY StartDate;
```

このようにマテリアライズド・ビューを作成し、データ集約を完了させたノーマル・ビューを割り当てる事が出来ます。

ほとんどの場合、AggregtingMergeTreeの利用は正当ではない事に注意してください。これは、集計されていないデータに対してクエリを効率的に実行させるエンジンです。

## CollapsingMergeTree

このエンジンは、Yandex.Metrica専用です。

これはMergeTreeと違い、マージ時に自動的に削除されたり、特定の行のペアが"折りたたまれ"ます。

(以下略)

## GraphiteMergeTree

このエンジンは、ロールアップ(間引き及び集約/平均化)グラファイトデータ用に設計されています。ClickHouseをGraphiteのデータストアとして使用したい開発者にとって役立つかも知れません。

(以下略)

## Data replication

レプリケーションは、MergeTreeファミリーのテーブルでのみサポートされます。レプリケーションは、サーバー全体ではなく、個々のテーブルのレベルで機能します。サーバーはレプリケーションテーブルと(レプリケーションされてない)テーブルの両方を同時に保存する事が出来ます。

INSERTとALTERは複製されます(詳細はALTERの項を参照)。圧縮データは複製され、クエリテキストは複製されません。CREATE, DROP, ATTACH, DETACH及びRENAMEクエリは複製されません。つまり、それらは単一のサーバーに属します。CREATE TABLEクエリはクエリが実行されるサーバー上に新しい複製可能なテーブルを作成します。このテーブルが他のサーバー上で既に存在する場合は、新しいレプリカが追加されます。DROP TABLEクエリはクエリが実行されているサーバー上にあるレプリカを削除します。RENAMEクエリは、レプリカの1つのテーブルの名前を変更します。つまり、複製されたテーブルは、異なるレプリカ上で異なる名前を持つ事が出来ます。

レプリケーションはシャーディングとは関係ありません。複製は各シャードで独立して機能します。

レプリケーションはオプション機能です。レプリケーションを使用するには、設定ファイルで [ZooKeeper](https://zookeeper.apache.org/) クラスタのアドレスを設定します。例:

```
<zookeeper>
    <node index="1">
        <host>example1</host>
        <port>2181</port>
    </node>
    <node index="2">
        <host>example2</host>
        <port>2181</port>
    </node>
    <node index="3">
        <host>example3</host>
        <port>2181</port>
    </node>
</zookeeper>
```

ZooKeeperバージョン3.4.5以降。例えば、Ubuntu Preciseパッケージでは古すぎます。

既存の任意のZooKeeperクラスタを指定する事が出来、システムは自身のデータ用にディレクトリを指定します。(ディレクトリは、複製可能なテーブルの作成時に指定されます)

ZooKeeperが設定ファイルに設定されていない場合、複製テーブルを作成する事は出来ず、既存の複製テーブルは読み取り専用になります。

ZooKeeperはSELECTクエリには使用されません。つまり、レプリケーションはSELECTクエリの生産性に影響を与えません。レプリケーションされていないテーブルの場合と同じくらい高速に動作します。ClickHouseの動作では、分散レプリケートテーブルを紹介するとき、 
 `max_replica_delay_for_distributed_queries` と `fallback_to_stale_replicas_for_distributed_queries` の設定によって制御されます。

INSERTクエリ毎に、いくつかのトランザクションで約10個のエントリがZooKeeperで作成されます。これにより、レプリケートされていないテーブルと比較して、INSERTの待機時間が若干長くなります。しかし、1秒あたり1回以上のINSERTバッチでデータを挿入するための推奨事項に従えば、問題は発生しません。1つのZooKeeperクラスタを調整するために使用されるClickHouseクラスタ全体には、毎秒数百のINSERTを可能にします。データ挿入時のスループット(1秒あたりの行数)は、レプリケーションされていないDBのスループットと同じです。

非常に大規模なクラスタの場合、異なるシャードに対して異なるZooKeeperクラスタを使用できます。しかし、これはYandex.Metricaクラスタ(約300台のサーバー)では必要ではない事が証明されています。

レプリケーションは非同期及びマルチマスターです。INSERTクエリ(及びALTER)は、使用可能な任意のサーバーに送信できます。データは任意のサーバーで挿入され、他のサーバーに送信(同期)されます。ただし非同期であるため、最近挿入されたデータは、他のレプリカ上にいくらかの遅延を伴って同期されます。レプリカの一部が使用できない場合、それらのデータは使用可能になると書き込まれます。レプリカが使用可能な場合、発生する遅延は、圧縮されたデータのブロックをネットワーク経由で転送するのにかかる時間必要です。

`quorum` の書き込みはありません。(?) 複数のレプリカにデータが送信された事を確認できる書き込み方法はありません。1つのレプリカにデータのバッチを書き込む処理で、他のレプリカにデータを送る前、自身がいなくなった場合(ダウンした場合)、データは失われます。

データの各ブロックはアトミックに書き込まれます。INSERTクエリは、 `max_insert_block_size = 1048576` 行までのブロックに分割されます。つまり、INSERTクエリの行数が `1048576` 未満の場合、それはアトミックになります。

データブロックは重複排除されます。同じデータブロック(同じ順序の同じ行を含む同じサイズのデータブロック)を複数回書き込む場合、ブロックは1回だけ書き込まれます。この理由は、クライアントアプリケーションがデータをDBに書き込まれたかわからない状態でネットワークが落ちるケースで、INSERTクエリがシンプルに繰り返す事が出来ます。どのレプリカのINSERTが同じデータを送ったかは重要ではありません。(?) INSERTは冪等です。これはテーブルにINSERTされた最後の100ブロックでのみ機能します。(?)

レプリケーション中は、INSERTするソースデータのみがネットワーク経由で転送されます。さらにデータ変換(マージ)は、同じ方法で全てのレプリカに対して調整され、実行されます。これにより、ネットワークの使用が最小限に抑えられます。つまり、レプリケーションが異なるデータセンターに存在する場合、複製が上手く機能します。(異なるデータセンターにデータを複製する事は、複製の主な目的です。)

同じデータを任意の数のレプリカに持つ事が出来ます。Yandex.Metricaは本番環境で十のレプリケーションを使用しています。各サーバーは、場合によってはRAID5またはRAID6、及びRAID10を使用しています。これは比較的信頼できる便利なソリューションです。

システムは、レプリカ上のデータの同期生を監視し、障害後に回復する事が出来ます。フェイルオーバーは自動(データの違いが小さい場合)または半自動(データが多すぎると公正エラーを出す可能性がある)です。

### Creating replicated tables

(省略)

### Recovery after failures

(省略)

### Recovery after complete data loss

(省略)

### Converting from MergeTree to ReplicatedMergeTree

(省略)

### Converting from ReplicatedMergeTree to MergeTree

(省略)

### Recovery when metadata in the ZooKeeper cluster is lost or damaged

(省略)

## Distributed

(省略)

## Dictionary

(省略)

## Merge

Merge エンジン([MergeTree](#mergetree) とは別です)は、データそのものを格納するのではなく、任意の数、他のテーブルから同時に読み取ることができます。読み取りは自動的に入れ尽かされます。テーブルへの書き込みはサポートされません。読み込み時に、実際に読み込んでいるテーブルのもつインデックスが使用されます。Mergeエンジンはパラメータを受け取ります。データベース名とテーブル名の正規表現です。

例:

```
Merge(hits, '^WatchLog')
```

`hits` データベースの、正規表現 `'^WatchLog'` と一致する名前を持つテーブルからデータが読み込まれます。データベース名の代わりに、文字列を返す定数式を使用できます。例えば、 `currentDatabase()` 等。

正規表現は [`re2`](https://github.com/google/re2)(PCREに似ています) を使用しています。大文字と小文字が区別されます。 `"match"` セクションの正規表現でのエスケープ記号に注意してください。

読み込むテーブルを選択するとき、Mergeテーブル自体は正規表現と一致していても選択されません。これはループを避けるためです。無限にお互いのデータを読み取ろうとする2つのMergeテーブルを作成する事は可能ですが、しないでください。
Mergeエンジンを利用する典型的なケースは、1つのテーブルで多数の [TinyLog](#tinylog) テーブルを操作する事です。

### Virtual columns

仮想列(Virtual columns)は、テーブルの定義に関係なく、テーブルエンジンによって提供される列です。つまり、これらの列は CREATE TABLE では指定されていませんが、 SELECT でアクセス可能です。

仮想列とは、通常の列と次の点で異なります。

* これらはTABLE定義では指定されません。
* INSERTデータで追加する事は出来ません。
* 列のリストを指定せずにINSERTすると、仮想列は無視されます。
* アスタリスク (SELECT *) を使用するときは選択されません。
* 仮想列は、 `SHOW CREATE TABLE` 及び `DESC TABLE` クエリには表示されません。

Merge タイプのテーブルには、String型の仮想の `'_table'` カラムが含まれています。(テーブルに `'_table'` カラムがある場合、 `'_table1'` という名前になり、更に `'_table1'` があるのなら `'_table2'` になります。)このカラムにはテーブルの名前が格納されます。

WHERE句またはPREWHRE句に、他の表の列に依存しない `'_table'` カラムの条件が含まれている場合、これらの条件はインデックスとして使用されます。(?) 条件は、データを読み込むためのテーブル名のデータ・セットに対して実行され、読み取り操作は、条件がトリガーされた `'_table'` からのみ実行されます。

## Buffer

(省略)

## File(InputFormat)

(省略)

## Null

(省略)

## Set

(省略)

## Join

(省略)

## View

(省略)

## MaterializedView

(省略)

## Kafka

(省略)

## External data for query processing

(省略)