バージョンごとのドキュメント一覧

29.7. コンフリクト #

<title>Conflicts</title>

Logical replication behaves similarly to normal DML operations in that the data will be updated even if it was changed locally on the subscriber node. If incoming data violates any constraints the replication will stop. This is referred to as a <firstterm>conflict</firstterm>. When replicating <command>UPDATE</command> or <command>DELETE</command> operations, missing data is also considered as a <firstterm>conflict</firstterm>, but does not result in an error and such operations will simply be skipped. サブスクライバーノードでローカルにデータが変更された場合でも、データが更新されるという点では、論理レプリケーションは通常のDML操作と同じように振る舞います。 到着したデータが制約に違反すると、レプリケーションは停止します。 これは、コンフリクトと呼ばれます。 UPDATEあるいはDELETE操作をレプリケーションする場合は、存在しないデータもコンフリクトとみなされますが、エラーにはならずそのような操作は単にスキップされます。

Additional logging is triggered, and the conflict statistics are collected (displayed in the <link linkend="monitoring-pg-stat-subscription-stats"><structname>pg_stat_subscription_stats</structname></link> view) in the following <firstterm>conflict</firstterm> cases: 次のコンフリクトの場合、追加のログが出力され、統計情報が収集されます(pg_stat_subscription_statsビューに出力されます)。

insert_exists #

Inserting a row that violates a <literal>NOT DEFERRABLE</literal> unique constraint. Note that to log the origin and commit timestamp details of the conflicting key, <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link> should be enabled on the subscriber. In this case, an error will be raised until the conflict is resolved manually. NOT DEFERRABLEな一意性制約に違反する行を挿入しています。 競合するキーのオリジンやコミットタイムスタンプの詳細をログ出力するためには、サブスクライバーでtrack_commit_timestampを有効にする必要があります。 この場合、コンフリクトが手動で解決されるまで、エラーが報告されます。

update_origin_differs #

Updating a row that was previously modified by another origin. Note that this conflict can only be detected when <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link> is enabled on the subscriber. Currently, the update is always applied regardless of the origin of the local row. 以前別のオリジンによって変更された行を更新しています。 このコンフリクトは、サブスクライバーでtrack_commit_timestampを有効にしている場合にのみ検出されます。 現在のところ、更新はローカル行のオリジンに関係なく常に適用されます。

update_exists #

The updated value of a row violates a <literal>NOT DEFERRABLE</literal> unique constraint. Note that to log the origin and commit timestamp details of the conflicting key, <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link> should be enabled on the subscriber. In this case, an error will be raised until the conflict is resolved manually. Note that when updating a partitioned table, if the updated row value satisfies another partition constraint resulting in the row being inserted into a new partition, the <literal>insert_exists</literal> conflict may arise if the new row violates a <literal>NOT DEFERRABLE</literal> unique constraint. 行の更新された値がNOT DEFERRABLEな一意性制約に違反しています。 競合するキーのオリジンやコミットタイムスタンプの詳細をログ出力するためには、サブスクライバーでtrack_commit_timestampを有効にする必要があります。 この場合、コンフリクトが手動で解決されるまで、エラーが報告されます。 パーティションテーブルを更新するときに、更新した行が別のパーティション制約を満たし、その結果行が別のパーティションに挿入される場合、新しい行がNOT DEFERRABLEな一意性制約に違反すると、insert_existsコンフリクトが検出される可能性があることに注意してください。

update_missing #

The row to be updated was not found. The update will simply be skipped in this scenario. 更新対象の行が見つかりませんでした。 このシナリオでは更新は単純にスキップされます。

delete_origin_differs #

Deleting a row that was previously modified by another origin. Note that this conflict can only be detected when <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link> is enabled on the subscriber. Currently, the delete is always applied regardless of the origin of the local row. 以前別のオリジンによって変更された行を削除しています。 このコンフリクトは、サブスクライバーでtrack_commit_timestampを有効にしている場合にのみ検出されます。 現在のところ、削除はローカル行のオリジンに関係なく常に適用されます。

delete_missing #

The row to be deleted was not found. The delete will simply be skipped in this scenario. 削除対象の行が見つかりませんでした。 このシナリオでは削除は単純にスキップされます。

multiple_unique_conflicts #

Inserting or updating a row violates multiple <literal>NOT DEFERRABLE</literal> unique constraints. Note that to log the origin and commit timestamp details of conflicting keys, ensure that <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link> is enabled on the subscriber. In this case, an error will be raised until the conflict is resolved manually. 挿入または更新行が、複数のNOT DEFERRABLEな一意性制約に違反しています。 このコンフリクトは、サブスクライバーでtrack_commit_timestampを有効にしている場合にのみ検出されます。 この場合、コンフリクトが手動で解決されるまで、エラーが報告されます。

Note that there are other conflict scenarios, such as exclusion constraint violations. Currently, we do not provide additional details for them in the log. 排他制約違反など、他にもコンフリクトのシナリオが存在することに注意してください。 現在のところ、ログにはこれらのコンフリクトに関する詳細情報は出力されません。

The log format for logical replication conflicts is as follows: 論理レプリケーションコンフリクトのログフォーマットは以下の通りです。

LOG:  conflict detected on relation "schemaname.tablename": conflict=conflict_type
DETAIL:  detailed_explanation.
{detail_values [; ... ]}.

where detail_values is one of:

    Key (column_name [, ...])=(column_value [, ...])
    existing local row [(column_name [, ...])=](column_value [, ...])
    remote row [(column_name [, ...])=](column_value [, ...])
    replica identity {(column_name [, ...])=(column_value [, ...]) | full [(column_name [, ...])=](column_value [, ...])}

The log provides the following information: ログには次の情報が提供されます。

LOG
  • <replaceable>schemaname</replaceable>.<replaceable>tablename</replaceable> identifies the local relation involved in the conflict. schemaname.tablenameは、コンフリクトに関係するローカルリレーションを識別します。

  • <replaceable>conflict_type</replaceable> is the type of conflict that occurred (e.g., <literal>insert_exists</literal>, <literal>update_exists</literal>). conflict_typeは発生したコンフリクトの種類です(例:insert_existsupdate_exists)。

DETAIL
  • <replaceable class="parameter">detailed_explanation</replaceable> includes the origin, transaction ID, and commit timestamp of the transaction that modified the existing local row, if available. detailed_explanationには、既存のローカル行を変更したトランザクションのオリジンとトランザクションID、そしてコミットタイムスタンプ(利用可能であれば)が含まれます。

  • The <literal>Key</literal> section includes the key values of the local row that violated a unique constraint for <literal>insert_exists</literal>, <literal>update_exists</literal> or <literal>multiple_unique_conflicts</literal> conflicts. Keyセクションには、insert_existsupdate_existsまたはmultiple_unique_conflictsコンフリクトの一意性制約に違反したローカル行のキー値が含まれます。

  • The <literal>existing local row</literal> section includes the local row if its origin differs from the remote row for <literal>update_origin_differs</literal> or <literal>delete_origin_differs</literal> conflicts, or if the key value conflicts with the remote row for <literal>insert_exists</literal>, <literal>update_exists</literal> or <literal>multiple_unique_conflicts</literal> conflicts. existing local rowセクションにはローカル行が含まれます。 ただし、update_origin_differsまたはdelete_origin_differsコンフリクトではローカル行のオリジンがリモートと異なる場合、insert_existsupdate_existsまたはmultiple_unique_conflictsではキー値がリモート行と競合する場合です。

  • The <literal>remote row</literal> section includes the new row from the remote insert or update operation that caused the conflict. Note that for an update operation, the column value of the new row will be null if the value is unchanged and toasted. remote rowセクションには、競合の原因となったリモート挿入または更新操作による新しい行が含まれます。 更新操作の場合、変更されなかった列やTOASTされた列の値はNULLとなることに注意してください。

  • The <literal>replica identity</literal> section includes the replica identity key values that were used to search for the existing local row to be updated or deleted. This may include the full row value if the local relation is marked with <link linkend="sql-altertable-replica-identity-full"><literal>REPLICA IDENTITY FULL</literal></link>. replica identityセクションには、更新または削除対象となったローカル行の検索に使用されたレプリカアイデンティティが含まれます。 ローカルリレーションにREPLICA IDENTITY FULLが指定されている場合は、行全体の値が含まれることがあります。

  • <replaceable class="parameter">column_name</replaceable> is the column name. For <literal>existing local row</literal>, <literal>remote row</literal>, and <literal>replica identity full</literal> cases, column names are logged only if the user lacks the privilege to access all columns of the table. If column names are present, they appear in the same order as the corresponding column values. column_nameは列名です。 existing local row, remote row、およびreplica identity fullの場合、ユーザがテーブルのすべての列に対するアクセス権限を持っていない場合にのみ列名が記録されます。 列名が存在する場合は、対応する列の値と同じ順に表示されます。

  • <replaceable class="parameter">column_value</replaceable> is the column value. The large column values are truncated to 64 bytes. column_valueは列の値です。 長い列の値は64バイトに切り詰められます。

  • Note that in case of <literal>multiple_unique_conflicts</literal> conflict, multiple <replaceable class="parameter">detailed_explanation</replaceable> and <replaceable class="parameter">detail_values</replaceable> lines will be generated, each detailing the conflict information associated with distinct unique constraints. multiple_unique_conflictsコンフリクトの場合は、複数のdetailed_explanationおよびdetail_valuesが生成され、それぞれが異なる一意性制約に関連付けられたコンフリクト情報を詳述することに注意してください。

Logical replication operations are performed with the privileges of the role which owns the subscription. Permissions failures on target tables will cause replication conflicts, as will enabled <link linkend="ddl-rowsecurity">row-level security</link> on target tables that the subscription owner is subject to, without regard to whether any policy would ordinarily reject the <command>INSERT</command>, <command>UPDATE</command>, <command>DELETE</command> or <command>TRUNCATE</command> which is being replicated. This restriction on row-level security may be lifted in a future version of <productname>PostgreSQL</productname>. 論理レプリケーション操作は、サブスクリプションを所有するロールの権限を使用して実行されます。 対象テーブルで権限違反が起こると、レプリケーション競合が発生します。 これは、サブスクリプション所有者が従う、対象テーブルで有効な行レベルセキュリティと同じですが、レプリケーションされているINSERTUPDATEDELETEまたはTRUNCATEをポリシーが通常拒否するかどうかには関係ありません。 行レベルセキュリティに対するこの制限は、PostgreSQLの将来のバージョンで解除される可能性があります。

A conflict that produces an error will stop the replication; it must be resolved manually by the user. Details about the conflict can be found in the subscriber's server log. コンフリクトはエラーを生じさせ、レプリケーションを停止させます。 コンフリクトはユーザが手動で解消しなければなりません。 コンフリクトの詳細は、サブスクライバーのサーバログに出力されます。

The resolution can be done either by changing data or permissions on the subscriber so that it does not conflict with the incoming change or by skipping the transaction that conflicts with the existing data. When a conflict produces an error, the replication won't proceed, and the logical replication worker will emit the following kind of message to the subscriber's server log: この問題を解決するには、データを変更するか、サブスクライバーに対する権限を変更して、既存の変更でコンフリクトしないようにするか、既存のトランザクションと競合するデータをスキップします。 コンフリクトよってエラーが発生した場合、レプリケーションは処理を続行せず、論理レプリケーションワーカーは次のようなメッセージをサブスクライバーのサーバログに送信します。

ERROR:  conflict detected on relation "public.test": conflict=insert_exists
DETAIL:  Key already exists in unique index "t_pkey", which was modified locally in transaction 740 at 2024-06-26 10:47:04.727375+08.
Key (c)=(1); existing local row (1, 'local'); remote row (1, 'remote').
CONTEXT:  processing remote data for replication origin "pg_16395" during "INSERT" for replication target relation "public.test" in transaction 725 finished at 0/14C0378

The LSN of the transaction that contains the change violating the constraint and the replication origin name can be found from the server log (LSN 0/14C0378 and replication origin <literal>pg_16395</literal> in the above case). The transaction that produced the conflict can be skipped by using <link linkend="sql-altersubscription-params-skip"><command>ALTER SUBSCRIPTION ... SKIP</command></link> with the finish LSN (i.e., LSN 0/14C0378). The finish LSN could be an LSN at which the transaction is committed or prepared on the publisher. Alternatively, the transaction can also be skipped by calling the <link linkend="pg-replication-origin-advance"> <function>pg_replication_origin_advance()</function></link> function. Before using this function, the subscription needs to be disabled temporarily either by <link linkend="sql-altersubscription-params-disable"> <command>ALTER SUBSCRIPTION ... DISABLE</command></link> or, the subscription can be used with the <link linkend="sql-createsubscription-params-with-disable-on-error"><literal>disable_on_error</literal></link> option. Then, you can use <function>pg_replication_origin_advance()</function> function with the <parameter>node_name</parameter> (i.e., <literal>pg_16395</literal>) and the next LSN of the finish LSN (i.e., 0/14C0379). The current position of origins can be seen in the <link linkend="view-pg-replication-origin-status"> <structname>pg_replication_origin_status</structname></link> system view. Please note that skipping the whole transaction includes skipping changes that might not violate any constraint. This can easily make the subscriber inconsistent. The additional details regarding conflicting rows, such as their origin and commit timestamp can be seen in the <literal>DETAIL</literal> line of the log. But note that this information is only available when <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link> is enabled on the subscriber. Users can use this information to decide whether to retain the local change or adopt the remote alteration. For instance, the <literal>DETAIL</literal> line in the above log indicates that the existing row was modified locally. Users can manually perform a remote-change-win. 制約とレプリケーションの起点名に違反する変更を含むトランザクションのLSNは、サーバログ(LSN 0/14C0378とレプリケーション起点pg_16395)から見つけることができます。 競合を発生させたトランザクションは、終了LSN(LSN 0/14C0378)でALTER SUBSCRIPTION ... SKIPを使用してスキップできます。 終了LSNは、パブリッシャーでトランザクションがコミットまたは準備されたLSNにすることができます。 あるいは、pg_replication_origin_advance()関数を呼び出して、トランザクションをスキップすることもできます。 この関数を使用する前に、ALTER SUBSCRIPTION ... DISABLEを使用してサブスクリプションを一時的に無効にするか、 disable_on_errorオプションを使用します。 次に、pg_replication_origin_advance()関数をnode_name(pg_16395)と終了LSNの次のLSN(0/14C0379)と共に使用します。 現在の起点の位置は、pg_replication_origin_status システムビューで確認できます。 トランザクション全体をスキップすることは、いかなる制約にも違反しない可能性のある変更をスキップすることを含むことに注意してください。 これは容易にサブスクライバーを不整合にする可能性があります。 オリジンやコミットタイムスタンプのようなコンフリクト行に関する詳細は、ログのDETAIL行で確認できます。 しかし、これらの情報は、サブスクライバーでtrack_commit_timestampが有効な場合にのみ表示されます。 この情報はローカルの変更を保持するか、リモートの変更を採用するかを決定する際に使用できます。 例えば上記ログのDETAILは、既存の行がローカルで変更されたことを示しています。 ユーザは手動でリモート変更優先を実行できます。

When the <link linkend="sql-createsubscription-params-with-streaming"><literal>streaming</literal></link> mode is <literal>parallel</literal>, the finish LSN of failed transactions may not be logged. In that case, it may be necessary to change the streaming mode to <literal>on</literal> or <literal>off</literal> and cause the same conflicts again so the finish LSN of the failed transaction will be written to the server log. For the usage of finish LSN, please refer to <link linkend="sql-altersubscription"><command>ALTER SUBSCRIPTION ... SKIP</command></link>. streamingモードがparallelの場合、失敗したトランザクションの終了LSNはログに書き込まれないことがあります。 その場合、ストリーミングモードをonまたはoffに変更し、再度同じコンフリクトを起こすことで、失敗したトランザクションの終了LSNをサーバのログに書き込むようにする必要があるかもしれません。 終了LSNの使用方法については、ALTER SUBSCRIPTION ... SKIPを参照してください。