このトピックでは、Hologres で INSERT ON CONFLICT 文を使用する方法について説明します。
利用シーン
INSERT ON CONFLICT コマンドは、SQL 文を使用してデータをインポートするシナリオに適しています。
Data Integration または Flink を使用してデータを書き込む場合、次の設定を構成して、重複するプライマリキーを持つ行を更新またはスキップできます。
-
DataWorks の Data Integration 機能を使用したデータのインポート
Data Integration には、
INSERT ON CONFLICT機能が組み込まれています。この機能の仕組みの詳細については、「Hologres Writer」をご参照ください。次の設定を構成できます。-
オフラインデータ同期の場合、[書き込み競合ポリシー] を [無視] または [置換] に設定します。
-
リアルタイムデータ同期の場合、[書き込み競合ポリシー] を [無視] または [置換] に設定できます。
説明同期中にデータを更新するには、Hologres テーブルにプライマリキーを設定する必要があります。
-
-
Flink を使用したデータの書き込み
Flink を使用してデータを書き込む場合、デフォルトの [書き込み競合ポリシー] は
InsertOrIgnoreです。このポリシーでは、Hologres テーブルにプライマリキーを設定する必要があります。その後、最初のデータエントリを保持し、後続の重複するエントリはすべて無視します。ctas構文を使用する場合、デフォルトの [書き込み競合ポリシー] はInsertOrUpdateであり、既存のデータを置き換えます。
コマンドの概要
INSERT ON CONFLICT 文は、指定された列にデータの行を挿入します。重複するプライマリキーを持つ行が存在する場合、この文は既存の行を更新するか、挿入をスキップします。これにより、UPSERT (INSERT または UPDATE) 機能が提供されます。INSERT ON CONFLICT 文の構文は次のとおりです。
INSERT INTO <table_name> [ AS <alias> ] [ ( <column_name> [, ...] ) ]
{ VALUES ( { <expression> } [, ...] ) [, ...] | <query> }
[ ON CONFLICT [ conflict_target ] conflict_action ]
where conflict_target is pk
ON CONSTRAINT constraint_name
and conflict_action is one of:
DO NOTHING
DO UPDATE SET { <column_name> = { <expression> } |
( <column_name> [, ...] ) = ( { <expression> } [, ...] ) |
} [, ...]
[ WHERE condition ]
次の表に各パラメーターを説明します。
|
パラメーター |
説明 |
|
table_name |
データの挿入先となるテーブルの名前。 |
|
alias |
エイリアス。これは、宛先テーブルの代替名です。 |
|
column_name |
宛先テーブルのターゲット列の名前。 |
|
DO NOTHING |
InsertOrIgnore。指定された列に行を挿入する際に、重複するプライマリキーを持つ行が存在する場合、挿入はスキップされます。 |
|
DO UPDATE |
InsertOrUpdate。指定された列に行を挿入する際に、重複するプライマリキーを持つ行が存在する場合、既存の行が更新されます。 次のケースがあります。
重要
|
|
expression |
対応する列に対して実行される式。PostgreSQL を参照して式を設定できます。 一般的な式には、 |
仕組み
INSERT ON CONFLICT 機能は、UPDATE 文と同じように機能します。詳細については、「UPDATE」をご参照ください。更新プロセスは、行指向、列指向、行列表ハイブリッドストレージなど、テーブルのストレージフォーマットによってわずかに異なります。これにより、異なるストレージフォーマットを使用するテーブルを更新する際にパフォーマンスに差が生じます。ビジネス要件に基づき、INSERT ON CONFLICT は InsertOrIgnore、InsertOrReplace、または InsertOrUpdate に分類できます。次の表にその違いを説明します。
|
更新モード |
説明 |
|
InsertOrIgnore |
書き込み中に更新を無視します。結果テーブルにプライマリキーがあり、リアルタイム書き込み中に重複するプライマリキーが検出された場合、後のデータは破棄されます。これは |
|
InsertOrUpdate |
書き込み中にデータを更新します。結果テーブルにプライマリキーがあり、リアルタイム書き込み中に重複するプライマリキーが検出された場合、データはプライマリキーに基づいて更新されます。このモードには、全行更新と部分列更新が含まれます。部分列更新では、入力行にすべての列が含まれていない場合、欠落している列は更新されません。これは |
|
InsertOrReplace |
書き込み中にデータを上書きします。結果テーブルにプライマリキーがあり、リアルタイム書き込み中に重複するプライマリキーが検出された場合、データはプライマリキーに基づいて更新されます。入力行にすべての列が含まれていない場合、欠落している列は null 値で埋められます。これは |
UPDATE 文の仕組みに基づき、異なるモードでの更新パフォーマンスは、テーブルのストレージフォーマットによって異なります。
-
列指向テーブルの異なる書き込みモードのパフォーマンスは、次のようにランク付けされます。
-
結果テーブルにプライマリキーがない場合、パフォーマンスは最高になります。
-
結果テーブルにプライマリキーがある場合:
InsertOrIgnore > InsertOrReplace >= InsertOrUpdate (全行) > InsertOrUpdate (部分列)。
-
-
行指向テーブルの異なる書き込みモードのパフォーマンスは、次のようにランク付けされます。
InsertOrReplace = InsertOrUpdate (全行) >= InsertOrUpdate (部分列) >= InsertOrIgnore。
制限事項
-
INSERT ON CONFLICT文の条件には、すべてのプライマリキーを含める必要があります。 -
Hologres 高 QPS エンジン (HQE) が INSERT ON CONFLICT 文を実行する場合、操作の順序は保証されません。したがって、keep-first または keep-last のセマンティクスを実現することはできません。動作は keep-any です。実際には、データソースに削除する必要のある重複するプライマリキーが含まれている場合、次のコマンドを実行することで keep-last セマンティクスを使用できます。
-- 重複行の最後を保持します。 set hg_experimental_affect_row_multiple_times_keep_last = on;
例
-
INSERT ON CONFLICT文の使用例:説明Hologres V2.1.17 以降では、サーバーレスコンピューティングがサポートされています。大規模なオフラインデータインポート、大規模な抽出、変換、ロード (ETL) ジョブ、外部テーブルに対する大量のクエリなどのシナリオでは、サーバーレスコンピューティングを使用してこれらのタスクを実行できます。この機能は、ご利用のインスタンス独自のリソースの代わりに、追加のサーバーレスリソースを使用します。インスタンスに追加の計算リソースを予約する必要はありません。これにより、インスタンスの安定性が大幅に向上し、メモリ不足 (OOM) エラーの可能性が減少し、個々のタスクに対してのみ課金されます。サーバーレスコンピューティングの詳細については、「サーバーレスコンピューティング」をご参照ください。サーバーレスコンピューティングの使用方法については、「サーバーレスコンピューティングの使用ガイド」をご参照ください。
-
テーブルとデータの準備:
begin ; create table test1 ( a int NOT NULL PRIMARY KEY, b int, c int ); commit ; insert into test1 values (1,2,3); -
さまざまなシナリオの例を表示:
説明以下のシナリオ例は互いに独立しています。これらは順序どおりではなく、すべて前の手順で作成されたテーブルとデータに基づいています。
-
シナリオ 1:InsertOrIgnore 操作を実装します。重複するプライマリキーが存在する場合、行は更新されません。
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1) ON CONFLICT (a) DO NOTHING; -- 更新後の test1 テーブルのデータは次のとおりです。 a b c 1 2 3 -
シナリオ 2:全行更新のために InsertOrUpdate 操作を実装します。次のいずれかの方法を使用できます。
-
方法 1:
SET..EXCLUDED句にすべての列をリストします。INSERT INTO test1 (a, b, c) VALUES (1, 1, 1) ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b, c = EXCLUDED.c; -- 更新後の test1 テーブルのデータは次のとおりです。 a b c 1 1 1 -
方法 2:
ROW(EXCLUDED.*)を使用してすべての列を更新します。INSERT INTO test1 (a, b, c)VALUES (1, 1, 1) ON CONFLICT (a) DO UPDATE SET (a,b,c) = ROW(EXCLUDED.*); -- 更新後の test1 テーブルのデータは次のとおりです。 a b c 1 1 1
-
-
シナリオ 3:部分列更新のために InsertOrUpdate 操作を実装します。指定された列のみが更新され、欠落している列は更新されません。
-- 部分列更新を実行するには、SET の後に更新したい列をリストします。 INSERT INTO test1 (a, b, c) VALUES (1, 1, 1) ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b; -- テーブルの列 c は更新されません。更新後の test1 テーブルのデータは次のとおりです。 a b c 1 1 3 -
シナリオ 4:InsertOrReplace 操作を実装します。これにより、行全体が上書きされます。列が欠落している場合、それらは null 値で埋められます。
-- 欠落している列が null で埋められる InsertOrReplace 操作を実装するには、insert 値に手動で null を指定する必要があります。 INSERT INTO test1 (a, b,c) VALUES (1, 1,null) ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b,c = EXCLUDED.c; -- 更新後の test1 テーブルのデータは次のとおりです。 a b c 1 1 \N -
シナリオ 5:test1 テーブルのデータを別のテーブル test2 から更新します。
-- test2 テーブルとデータを準備します。 CREATE TABLE test2 ( d int NOT NULL PRIMARY KEY, e int, f int ); INSERT INTO test2 VALUES (1, 5, 6); -- test1 テーブルの行を、同じプライマリキーを持つ test2 テーブルの行で置き換えます。 INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET (a,b,c) = ROW (excluded.*); -- 更新後の test1 テーブルのデータは次のとおりです。 a b c 1 5 6 -- test1 テーブルの行を、同じプライマリキーを持つ test2 テーブルの行で置き換えますが、更新マッピングを調整します。test2 の列 e は列 c を更新し、test2 の列 f は列 b を更新します。 INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET (a,c,b) = ROW (excluded.*); -- 更新後の test1 テーブルのデータは次のとおりです。 a b c 1 6 5
-
-
-
行指向テーブルでの
INSERT ON CONFLICT文の最適化:Hologres は行指向テーブルの更新を最適化します。最高のパフォーマンスを得るには、UPDATE 句の列の順序を INSERT 句の順序と一致させ、全行更新を実行します。
INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET a = excluded.a, b = excluded.b, c = excluded.c; INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET(a,b,c) = ROW (excluded.*)
よくあるエラー
-
症状
データソースに対して
INSERT ON CONFLICT文を実行すると、次の 3 つのエラーのいずれかが発生します。-
エラー 1:
duplicate key value violates unique constraint。 -
エラー 2:
Update row with Key (xxx)=(yyy) multiple times。 -
エラー 3 (OOM 問題):
Total memory used by all existing queries exceeded memory limitation。
-
-
原因 1:データソースに重複データが含まれている。
Hologres は PostgreSQL と互換性があり、標準の PostgreSQL 構文を使用します。標準の PostgreSQL セマンティクスによれば、
INSERT ON CONFLICT文を実行する際、データソースに重複データを含めることはできません。データソースに重複データが含まれている場合、上記のエラーのいずれかが発生します。説明データソース内の重複データとは、挿入されるデータに重複行が含まれていることを意味し、挿入されるデータが宛先テーブルに重複していることを意味するものではありません。
次の例は、挿入されるデータに重複行が含まれている
INSERT ON CONFLICT文を示しています。INSERT INTO test1 VALUES (1, 2, 3), (1, 2, 3) ON CONFLICT (a) DO UPDATE SET (a, b, c) = ROW (excluded.*);解決策:
データソースに重複データが含まれている場合、次のパラメーターを設定して、重複行の最後を保持することができます。
set hg_experimental_affect_row_multiple_times_keep_last = on; -
原因 2:生存時間 (TTL) が期限切れになったため、データソースに重複データが含まれている。
データソースのテーブルには生存時間 (TTL) が設定されています。テーブル内の一部のデータが TTL を超えています。TTL のクリーンアップは瞬時に行われるわけではないため、期限切れのデータがすぐにクリアされない場合があります。これにより、インポート中に重複するプライマリキー (PK) データが発生し、エラーの原因となることがあります。
解決策:
Hologres V1.3.23 以降では、次のコマンドを使用して、期限切れの TTL によって引き起こされる重複 PK データを迅速に修正できます。このコマンドを実行すると、システムはテーブルから重複 PK データを削除します。デフォルトのクリーンアップポリシーは Keep Last で、重複の中から最後に書き込まれた行を保持し、その他を削除します。
説明-
原則として、PK は重複してはなりません。したがって、このコマンドは期限切れの TTL によって引き起こされた重複 PK のみをクリーンアップします。
-
このコマンドは Hologres V1.3.23 以降でのみ利用可能です。ご利用のインスタンスがそれより前のバージョンの場合は、インスタンスをアップグレードする必要があります。
call public.hg_remove_duplicated_pk('<schema>.<table_name>');例:2 つのテーブルがあるとします。
tbl_1は宛先テーブルで、tbl_2は TTL が300sのソーステーブルです。tbl_1をtbl_2のすべてのデータで更新したいとします。TTL が期限切れになると、tbl_2に重複するプライマリキーが表示され、エラーが発生します。BEGIN; CREATE TABLE tbl_1 ( a int NOT NULL PRIMARY KEY, b int, c int ); CREATE TABLE tbl_2 ( d int NOT NULL PRIMARY KEY, e int, f int ); CALL set_table_property('tbl_2', 'time_to_live_in_seconds', '300'); COMMIT; INSERT INTO tbl_1 VALUES (1, 1, 1), (2, 3, 4); INSERT INTO tbl_2 VALUES (1, 5, 6); -- 300 秒後、tbl_2 に再度データを挿入します。 INSERT INTO tbl_2 VALUES (1, 3, 6); -- tbl_1 の行を、同じプライマリキーを持つ tbl_2 の行で置き換えます。期限切れの TTL によって引き起こされた重複 PK のため、更新は失敗します。 INSERT INTO tbl_1 (a, b, c) SELECT d,e,f FROM tbl_2 ON CONFLICT (a) DO UPDATE SET (a,b,c) = ROW (excluded.*); -- エラーの原因:ERROR: internal error: Duplicate keys detected when building hash table. -- コマンドを使用して tbl_2 の重複 PK データをクリーンアップします。ポリシーは keep last です。 call public.hg_remove_duplicated_pk('tbl_2'); -- データを再度 tbl_1 にインポートします。データは正常にインポートされます。 -
-
原因 3:インスタンスのメモリリソースが不足しており、大量の書き込みタスクをサポートできない。
解決策:
-
Hologres のサーバーレスコンピューティング機能を使用して、大量の書き込みタスクを実行します。Hologres V2.1.17 以降では、サーバーレスコンピューティングがサポートされています。この機能は、大規模なオフラインデータインポート、大規模な ETL ジョブ、外部テーブルに対する大量のクエリに使用できます。サーバーレスコンピューティングは、ご利用のインスタンス独自のリソースの代わりに、追加のサーバーレスリソースを使用してこれらのタスクを実行します。これにより、インスタンスに追加の計算リソースを予約する必要がなくなります。このアプローチにより、インスタンスの安定性が大幅に向上し、OOM エラーの可能性が減少します。個々のタスクに対してのみ課金されます。詳細については、「サーバーレスコンピューティング」および「サーバーレスコンピューティングの使用ガイド」をご参照ください。
-
「一般的な OOM エラーのトラブルシューティング」で説明されている方法に従ってください。
-