mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-16 11:22:12 +00:00
398 lines
13 KiB
Markdown
398 lines
13 KiB
Markdown
|
---
|
|||
|
slug: /ja/guides/developer/deduplicating-inserts-on-retries
|
|||
|
title: 挿入操作の再試行時のデータ重複防止
|
|||
|
description: 挿入操作を再試行する際の重複データ防止策
|
|||
|
keywords: [重複排除, デデュプリケート, 挿入再試行, 挿入]
|
|||
|
---
|
|||
|
|
|||
|
挿入操作は、タイムアウトなどのエラーにより失敗することがあります。挿入が失敗した場合、データが成功裏に挿入されたかどうかは不明です。本ガイドでは、挿入再試行時に同じデータが複数回挿入されないように、データ重複防止機能を有効にする方法を説明します。
|
|||
|
|
|||
|
挿入が再試行されると、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`を計算します。これにより、マテリアライズドビュー内での正確な重複防止が保証され、元の挿入によってデータが区別され、マテリアライズドビューの対象テーブルに到達する前に加えられる変換にかかわらずデータが識別されます。
|
|||
|
|
|||
|
## 例
|
|||
|
|
|||
|
### マテリアライズドビューの変換後の同一ブロック
|
|||
|
|
|||
|
マテリアライズドビュー内での変換中に生成された同一ブロックは異なる挿入データに基づいているため、重複排除されません。
|
|||
|
|
|||
|
こちらは例です:
|
|||
|
|
|||
|
```sql
|
|||
|
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;
|
|||
|
```
|
|||
|
|
|||
|
```sql
|
|||
|
SET max_block_size=1;
|
|||
|
SET min_insert_block_size_rows=0;
|
|||
|
SET min_insert_block_size_bytes=0;
|
|||
|
```
|
|||
|
|
|||
|
上記の設定により、テーブルから一行のみを持つ一連のブロックを選択できます。これらの小さいブロックは圧縮されず、テーブルに挿入されるまでは同一のままです。
|
|||
|
|
|||
|
```sql
|
|||
|
SET deduplicate_blocks_in_dependent_materialized_views=1;
|
|||
|
```
|
|||
|
|
|||
|
マテリアライズドビューでの重複排除を有効にする必要があります:
|
|||
|
|
|||
|
```sql
|
|||
|
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パート。パートは異なるデータを含んでいます。
|
|||
|
|
|||
|
```sql
|
|||
|
SELECT
|
|||
|
*,
|
|||
|
_part
|
|||
|
FROM mv_dst
|
|||
|
ORDER by all;
|
|||
|
```
|
|||
|
|
|||
|
ここでは、`mv_dst`テーブルに2つのパートが挿入されたことが分かります。それらのパートは同じデータを含んでいますが、重複排除されていません。
|
|||
|
|
|||
|
```sql
|
|||
|
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`テーブルの両方で機能します。
|
|||
|
|
|||
|
## 挿入時の同一ブロック
|
|||
|
|
|||
|
```sql
|
|||
|
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;
|
|||
|
```
|
|||
|
|
|||
|
挿入:
|
|||
|
|
|||
|
```sql
|
|||
|
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`を使用した挿入時の同一ブロック
|
|||
|
|
|||
|
```sql
|
|||
|
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;
|
|||
|
```
|
|||
|
|
|||
|
挿入:
|
|||
|
|
|||
|
```sql
|
|||
|
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つの同一ブロックが期待通りに挿入されました。
|
|||
|
|
|||
|
```sql
|
|||
|
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;
|
|||
|
```
|
|||
|
|
|||
|
再試行挿入は期待通りに重複排除されます。
|
|||
|
|
|||
|
```sql
|
|||
|
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はデータのハッシュサムを使用しません。
|
|||
|
|
|||
|
## 異なる挿入操作がマテリアライズドビューの基になるテーブルで同じデータを生成する場合
|
|||
|
|
|||
|
```sql
|
|||
|
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`テーブルには同じデータが挿入されています。データは元のデータが異なっていたため、重複排除されません。
|
|||
|
|
|||
|
## 異なるマテリアライズドビューが同一のデータを基になるテーブルに挿入する場合
|
|||
|
|
|||
|
```sql
|
|||
|
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つの等しいブロックが挿入されました(期待通り)。
|
|||
|
|
|||
|
```sql
|
|||
|
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`テーブルの両方で重複排除されます。
|