ALTER TABLE クエリでは、テーブル設定またはデータを変更します。
ほとんどの
ALTER TABLE クエリは、*MergeTree、Merge、および Distributed テーブルでのみサポートされています。ALTER ステートメントはビューを操作します。
以下の
ALTER ステートメントは、ロールベースのアクセス制御に関連するエンティティを変更します。
ミューテーション
ALTER クエリは、「ミューテーション」と呼ばれる仕組みによって実装されています。代表的なものとして、ALTER TABLE … DELETE や ALTER TABLE … UPDATE があります。これらは、MergeTree テーブルにおけるマージと同様、新しい「変更後」のパーツを生成する非同期のバックグラウンド処理です。
*MergeTree テーブルでは、ミューテーションはデータパーツ全体を書き換えることで実行されます。
アトミック性はありません。パーツは準備ができ次第、変更後のパーツに置き換えられるため、ミューテーションの実行中に開始された SELECT クエリでは、すでに変更済みのパーツのデータと、まだ変更されていないパーツのデータの両方が見えることがあります。
ミューテーションは作成順に完全に順序付けられ、その順序で各パーツに適用されます。また、INSERT INTO クエリに対しては部分的な順序関係もあります。ミューテーションの送信前にテーブルへ挿入されたデータは変更対象になりますが、その後に挿入されたデータは変更されません。なお、ミューテーションが insert をブロックすることはありません。
ミューテーションのクエリは、ミューテーションエントリが追加されるとすぐに返ります (レプリケートテーブルの場合は ZooKeeper に、非レプリケートテーブルの場合は filesystem に追加されます) 。ミューテーション自体は、システムの profile 設定を使用して非同期に実行されます。ミューテーションの進行状況を追跡するには、system.mutations テーブルを使用できます。正常に送信されたミューテーションは、ClickHouse server が再起動しても実行が継続されます。いったん送信されたミューテーションをロールバックする方法はありませんが、何らかの理由で停止している場合は、KILL MUTATION クエリでキャンセルできます。
完了したミューテーションのエントリはすぐには削除されません (保持するエントリ数は、ストレージエンジンのパラメータ finished_mutations_to_keep で決まります) 。古いミューテーションエントリは削除されます。
ALTERクエリの同期
ALTER クエリが同期的に実行されます。レプリケートテーブルでは、クエリは対応する操作の指示を ZooKeeper に追加するだけで、操作自体はできるだけ早く実行されます。ただし、クエリはそれらの操作がすべてのレプリカで完了するまで待機できます。
ミューテーションを作成する ALTER クエリ (例: UPDATE、DELETE、MATERIALIZE INDEX、MATERIALIZE PROJECTION、MATERIALIZE COLUMN、APPLY DELETED MASK、APPLY PATCHES、CLEAR STATISTIC、MATERIALIZE STATISTIC など) については、同期性は mutations_sync 設定によって決まります。
メタデータのみを変更するその他の ALTER クエリについては、alter_sync 設定を使用して待機方法を設定できます。
非アクティブなレプリカがすべての ALTER クエリを実行するまで、どれだけ長く (秒単位で) 待機するかは、replication_wait_for_inactive_replica_timeout 設定で指定できます。
すべての
ALTER クエリについて、alter_sync = 2 であり、かつ一部のレプリカが replication_wait_for_inactive_replica_timeout 設定で指定された時間を超えて非アクティブな場合は、UNFINISHED 例外がスローされます。1 つのテーブルに対する ALTER の同時割り当て
ALTER ステートメントを短時間に連続して送信すると、CANNOT_ASSIGN_ALTER (コード 517) で失敗することがあります。レプリケートパスでは、レプリカが以前の ALTER の一部をまだ適用していない場合にこのエラーが発生します (メタデータバージョンが共通メタデータより遅れている状態です。サーバーは、レプリカについて「still not applied some of previous alters」または「Probably too many alters executing concurrently」と表示することがあります) 。以前の ALTER がすでに割り当てられた後でも、この状態が続くことがあります。これは メタデータ ALTER とミューテーションの一般的な同時実行状態 であり、ミューテーションのみを行うステートメントに限定されません。通常の同時メタデータ変更 (ADD / DROP / MODIFY など) でも、同じ再試行可能なコードが発生する場合があります (例として、tests/queries/0_stateless/03518_alter_logical_race.sh で対象となっている再試行パスを参照してください) 。
競合を回避する方法:
- 文法で許可される場合は、独立したメタデータ操作を 1 つの 複数句
ALTERにまとめます (たとえば、複数のADD INDEX句) 。 ALTERステートメントを直列化し、以前のALTERがレプリカに適用されるまで、コード 517 が発生した場合は再試行します。- ミューテーションを生成する
ALTERでは、次のALTERを送信する前に、mutations_syncやsystem.mutationsのis_doneなど、ドキュメント化された確認手段を使用して、以前のミューテーションが完了するのを待ちます。
MATERIALIZE INDEX 句の組み合わせ
ALTER に複数の MATERIALIZE INDEX 句を含めることができます。ツリー内でテスト対象となっているのは、複数の ADD INDEX 句と、それらの新しい索引に対する MATERIALIZE INDEX を 1 つのステートメントにまとめるケースです (tests/queries/0_stateless/02911_add_index_and_materialize_index.sql を参照) 。この ADD INDEX + MATERIALIZE INDEX をまとめた形式では、AlterCommand セグメントと MutationCommand セグメントが混在するため、DatabaseReplicated では QUERY_IS_PROHIBITED により拒否されます (InterpreterAlterQuery::validateReplicatedDatabaseSegments) 。通常の (非 DatabaseReplicated) データベースでは、02911 の例は有効です。DatabaseReplicated では、メタデータの変更とマテリアライズのミューテーションを別々のステートメントに分けてください。
現在の実装では、各 MATERIALIZE INDEX 句はミューテーションの準備時にテーブルのメタデータスナップショットに対して解決されます。そのため、既存の索引に対するマテリアライズのみの複数句形式も同じ準備パスをたどります (ミューテーションのみであるため、1 つのセグメント内に収まります) 。この正確な形式は、まだ専用のステートレステストでカバーされていません。そのようなテストが追加されるまでは、個別に保証された契約ではなく、現在の実装上の動作として扱ってください。
ミューテーションを順序どおりに適用する必要がある場合は、引き続きステートメントごとに 1 つの MATERIALIZE INDEX を実行し、mutations_sync で完了を待機できます。
- ブログ: ClickHouseでの更新と削除の処理