13 KiB
slug | title | description | keywords | ||||
---|---|---|---|---|---|---|---|
/ja/guides/developer/deduplicating-inserts-on-retries | 挿入操作の再試行時のデータ重複防止 | 挿入操作を再試行する際の重複データ防止策 |
|
挿入操作は、タイムアウトなどのエラーにより失敗することがあります。挿入が失敗した場合、データが成功裏に挿入されたかどうかは不明です。本ガイドでは、挿入再試行時に同じデータが複数回挿入されないように、データ重複防止機能を有効にする方法を説明します。
挿入が再試行されると、ClickHouseはデータが既に成功裏に挿入されたかどうかを判断しようとします。挿入されたデータが重複としてマークされる場合、ClickHouseはそれを対象のテーブルに挿入しません。しかし、ユーザーはあたかもデータが正常に挿入されたかのように成功操作ステータスを受け取ります。
再試行時の挿入重複防止の有効化
テーブルに対する挿入重複防止
*MergeTree
エンジンのみが挿入時の重複防止をサポートしています。
*ReplicatedMergeTree
エンジンに対しては、挿入重複防止はデフォルトで有効になっており、replicated_deduplication_window
およびreplicated_deduplication_window_seconds
設定によって制御されます。非レプリケートされた*MergeTree
エンジンに対しては、重複防止はnon_replicated_deduplication_window
設定によって制御されます。
上記の設定は、テーブルの重複防止ログのパラメータを決定します。この重複防止ログは有限の数のblock_id
を保持し、これにより重複防止の仕組みが決まります(以下参照)。
クエリレベルでの挿入重複防止
設定insert_deduplicate=1
を用いると、クエリレベルでの重複防止が有効になります。insert_deduplicate=0
でデータを挿入した場合、そのデータはinsert_deduplicate=1
で挿入を再試行しても重複防止されません。これは、block_id
がinsert_deduplicate=0
での挿入時に記録されないためです。
挿入重複防止の仕組み
データがClickHouseに挿入されるとき、行数とバイト数に基づいてデータがブロックに分割されます。
*MergeTree
エンジンを使用したテーブルでは、各ブロックにはそのブロック内のデータのハッシュである一意のblock_id
が割り当てられます。このblock_id
は挿入操作の一意キーとして使用されます。同じblock_id
が重複防止ログで見つかった場合、そのブロックは重複と見なされ、テーブルには挿入されません。
このアプローチは異なるデータを含む挿入の場合にうまく機能します。しかし、同じデータを複数回意図的に挿入する場合は、insert_deduplication_token
設定を使用して重複防止プロセスを制御する必要があります。この設定を用いると、各挿入に対して一意のトークンを指定でき、ClickHouseはこのトークンを利用してデータが重複かどうかを判断します。
INSERT ... VALUES
クエリの場合、挿入データのブロック分割は決定的であり、設定によって決定されます。したがって、初回操作と同じ設定値で挿入を再試行することをお勧めします。
INSERT ... SELECT
クエリの場合、クエリのSELECT
部分が各操作で同じ順序で同じデータを返すことが重要です。実際の使用においてこれは難しいことに留意してください。再試行で安定したデータ順序を確保するために、クエリのSELECT
部分で正確なORDER BY
セクションを定義してください。再試行間に選択されたテーブルが更新される可能性がある事にも注意が必要です。結果データが変更され、重複防止が行われない可能性があります。また、大量のデータを挿入する場合、挿入後のブロック数が重複防止ログウィンドウをオーバーフローすることがあり、ClickHouseがブロックを重複防止しない可能性があります。
マテリアライズドビューを使用した挿入重複防止
テーブルにマテリアライズドビューがある場合、そのビューの変換定義にしたがって挿入されたデータもビューの対象に挿入されます。変換されたデータも再試行時に重複を排除されます。ClickHouseはマテリアライズドビューに対しても、ターゲットテーブルに挿入されたデータと同様に重複を排除します。
このプロセスは以下のソーステーブル用の設定を使用して制御できます:
replicated_deduplication_window
replicated_deduplication_window_seconds
non_replicated_deduplication_window
また、ユーザープロファイル設定deduplicate_blocks_in_dependent_materialized_views
を使用することもできます。
マテリアライズドビュー下のテーブルへブロックを挿入する際、ClickHouseはソーステーブルのblock_id
と追加の識別子を組み合わせた文字列をハッシュしてblock_id
を計算します。これにより、マテリアライズドビュー内での正確な重複防止が保証され、元の挿入によってデータが区別され、マテリアライズドビューの対象テーブルに到達する前に加えられる変換にかかわらずデータが識別されます。
例
マテリアライズドビューの変換後の同一ブロック
マテリアライズドビュー内での変換中に生成された同一ブロックは異なる挿入データに基づいているため、重複排除されません。
こちらは例です:
CREATE TABLE dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;
CREATE MATERIALIZED VIEW mv_dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000
AS SELECT
0 AS key,
value AS value
FROM dst;
SET max_block_size=1;
SET min_insert_block_size_rows=0;
SET min_insert_block_size_bytes=0;
上記の設定により、テーブルから一行のみを持つ一連のブロックを選択できます。これらの小さいブロックは圧縮されず、テーブルに挿入されるまでは同一のままです。
SET deduplicate_blocks_in_dependent_materialized_views=1;
マテリアライズドビューでの重複排除を有効にする必要があります:
INSERT INTO dst SELECT
number + 1 AS key,
IF(key = 0, 'A', 'B') AS value
FROM numbers(2);
SELECT
*,
_part
FROM dst
ORDER by all;
ここでは、dst
テーブルに2つのパートが挿入されたことが分かります。選択からの2ブロック — 挿入時の2パート。パートは異なるデータを含んでいます。
SELECT
*,
_part
FROM mv_dst
ORDER by all;
ここでは、mv_dst
テーブルに2つのパートが挿入されたことが分かります。それらのパートは同じデータを含んでいますが、重複排除されていません。
INSERT INTO dst SELECT
number + 1 AS key,
IF(key = 0, 'A', 'B') AS value
FROM numbers(2);
SELECT
*,
_part
FROM dst
ORDER by all;
SELECT
*,
_part
FROM mv_dst
ORDER by all;
ここでは、挿入を再試行したとき、すべてのデータが重複排除されることが確認できます。重複排除はdst
テーブルとmv_dst
テーブルの両方で機能します。
挿入時の同一ブロック
CREATE TABLE dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;
SET max_block_size=1;
SET min_insert_block_size_rows=0;
SET min_insert_block_size_bytes=0;
挿入:
INSERT INTO dst SELECT
0 AS key,
'A' AS value
FROM numbers(2);
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
上記の設定で、選択結果から2つのブロックが生成され、その結果、テーブルdst
への挿入には2つのブロックがあるはずです。しかし、dst
テーブルには一つのブロックのみが挿入されたことが確認できます。これは、2番目のブロックが重複排除されたためです。挿入されたデータと、重複排除のキーであるblock_id
は挿入されたデータのハッシュとして計算されています。この動作は期待されたものではありません。このようなケースは稀ですが、理論的には可能です。このようなケースを正しく処理するために、ユーザーはinsert_deduplication_token
を提供する必要があります。以下の例でそれを修正しましょう:
insert_deduplication_token
を使用した挿入時の同一ブロック
CREATE TABLE dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;
SET max_block_size=1;
SET min_insert_block_size_rows=0;
SET min_insert_block_size_bytes=0;
挿入:
INSERT INTO dst SELECT
0 AS key,
'A' AS value
FROM numbers(2)
SETTINGS insert_deduplication_token='some_user_token';
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
2つの同一ブロックが期待通りに挿入されました。
select 'second attempt';
INSERT INTO dst SELECT
0 AS key,
'A' AS value
FROM numbers(2)
SETTINGS insert_deduplication_token='some_user_token';
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
再試行挿入は期待通りに重複排除されます。
select 'third attempt';
INSERT INTO dst SELECT
1 AS key,
'b' AS value
FROM numbers(2)
SETTINGS insert_deduplication_token='some_user_token';
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
この挿入も異なるデータを含んでいるにもかかわらず重複排除されています。insert_deduplication_token
の優先度が高いことに注意してください:insert_deduplication_token
が提供されると、ClickHouseはデータのハッシュサムを使用しません。
異なる挿入操作がマテリアライズドビューの基になるテーブルで同じデータを生成する場合
CREATE TABLE dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;
CREATE MATERIALIZED VIEW mv_dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000
AS SELECT
0 AS key,
value AS value
FROM dst;
SET deduplicate_blocks_in_dependent_materialized_views=1;
select 'first attempt';
INSERT INTO dst VALUES (1, 'A');
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
SELECT
'from mv_dst',
*,
_part
FROM mv_dst
ORDER by all;
select 'second attempt';
INSERT INTO dst VALUES (2, 'A');
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
SELECT
'from mv_dst',
*,
_part
FROM mv_dst
ORDER by all;
毎回異なるデータを挿入しています。しかし、mv_dst
テーブルには同じデータが挿入されています。データは元のデータが異なっていたため、重複排除されません。
異なるマテリアライズドビューが同一のデータを基になるテーブルに挿入する場合
CREATE TABLE dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;
CREATE TABLE mv_dst
(
`key` Int64,
`value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;
CREATE MATERIALIZED VIEW mv_first
TO mv_dst
AS SELECT
0 AS key,
value AS value
FROM dst;
CREATE MATERIALIZED VIEW mv_second
TO mv_dst
AS SELECT
0 AS key,
value AS value
FROM dst;
SET deduplicate_blocks_in_dependent_materialized_views=1;
select 'first attempt';
INSERT INTO dst VALUES (1, 'A');
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
SELECT
'from mv_dst',
*,
_part
FROM mv_dst
ORDER by all;
テーブルmv_dst
に2つの等しいブロックが挿入されました(期待通り)。
select 'second attempt';
INSERT INTO dst VALUES (1, 'A');
SELECT
'from dst',
*,
_part
FROM dst
ORDER by all;
SELECT
'from mv_dst',
*,
_part
FROM mv_dst
ORDER by all;
この再試行操作は、dst
テーブルとmv_dst
テーブルの両方で重複排除されます。