

# Aurora DSQL での同時実行制御
<a name="working-with-concurrency-control"></a>

同時実行により、複数のセッションがデータの整合性と一貫性を損なうことなく、同時にデータにアクセスして変更することができます。Aurora DSQL は、最新かつロックフリーの同時実行制御メカニズムを実装しながら、[PostgreSQL との互換性](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility.html)を提供します。スナップショットの分離を通じて完全な ACID コンプライアンスを維持し、データ整合性および信頼性を確保します。

Aurora DSQL の主なメリットは、一般的なデータベースパフォーマンスのボトルネックを排除するロックフリーのアーキテクチャです。Aurora DSQL は、遅いトランザクションが他のオペレーションをブロックするのを防ぎ、デッドロックのリスクを排除します。このアプローチにより、Aurora DSQL は、パフォーマンスと拡張性が重要な高スループットアプリケーションに特に役立ちます。

## 同時実行制御レスポンス
<a name="dsql-transaction-conflicts"></a>

Aurora DSQL は、オプティミスティック同時実行制御 (OCC) を使用します。これは、従来のロックベースのシステムとは動作が異なります。OCC はロックを使用する代わりに、コミット時に競合を評価します。このコミット時の競合評価プロセスは、判定とも呼ばれます。Aurora DSQL は、競合を検出すると、PostgreSQL シリアル化の失敗を示す SQLSTATE コード `40001` を返します。レスポンスメッセージには、競合のタイプを識別する OCC コードが含まれます。

**OC000 — データ競合**  
2 つのトランザクションが同じ行を変更しようとしました。コミット時間が最も早いトランザクションは成功し、競合するトランザクションは OC000 レスポンスを受け取ります。  

```
ERROR: change conflicts with another transaction (OC000) (SQLSTATE 40001)
```

**OC001 — スキーマ競合**  
セッションのキャッシュされたスキーマカタログが古くなっています。セッションがキャッシュをロードしてからカタログバージョンが変更されたことを Aurora DSQL が検出し、トランザクションが現在のバージョンに安全にリベースできない場合、トランザクションは OC001 レスポンスを受け取ります。  

```
ERROR: schema has been updated by another transaction (OC001) (SQLSTATE 40001)
```
スキーマカタログを変更するオペレーションでは、DDL ステートメント (`CREATE TABLE` や `ALTER TABLE` など)、`GRANT` ステートメント、`REVOKE` ステートメントなど、OC001 レスポンスが発生する可能性があります。詳細については、「[Aurora DSQL での DDL および分散トランザクション](working-with-ddl.md)」を参照してください。

これらのレスポンスを処理するには、再試行ロジックを実装するようにアプリケーションを設計します。理想的な設計パターンはべき等性であり、可能な限り最初の手段としてトランザクションの再試行を可能にします。推奨されるロジックは、標準 PostgreSQL のロックタイムアウトまたはデッドロック状況におけるアボートおよび再試行ロジックに似ています。ただし、OCC では、アプリケーションでこのロジックをより頻繁に実行する必要があります。

## データ競合タイプ
<a name="dsql-data-conflicts"></a>

Aurora DSQL の同時実行制御メカニズムにより、`SELECT ... FOR UPDATE` 句と `SELECT ... FOR KEY SHARE` 句は、ロックではなく、コミット時の楽観的な競合検出を通じて結果を生成します。Aurora DSQL では、あるトランザクションが行を書き込み、別のトランザクションが前述の句のいずれかを使用してその行を読み取ると、トランザクションが使用する列に応じて、コミット時に競合が発生する可能性があります。次の句は、Aurora DSQL がこれらの競合を検出する方法を決定します。

**キー列の定義**  
**キー列** とは、一意であり、部分的ではなく、式でもないインデックスのメンバーである列です。他のすべての列は非キー列です。

**`SELECT ... FOR UPDATE`**  
Aurora DSQL は、選択した行に対してトランザクションが書き込みを行ったかのように、行を判定することを宣言します。別のトランザクションが同じ行に対して `UPDATE`、`DELETE`、`SELECT ... FOR UPDATE`、または `SELECT ... FOR KEY SHARE` を実行して先にコミットした場合、`SELECT ... FOR UPDATE` を実行したトランザクションは失敗し、`OC000` レスポンスが返されます。この句は、行への同時書き込み、および同時 `FOR UPDATE` または `FOR KEY SHARE` 読み取りと競合します。

**`SELECT ... FOR KEY SHARE`**  
トランザクションが、選択した行のキー列に依存することを宣言します。別のトランザクションが行の削除、キー列の変更、または `SELECT ... FOR UPDATE` の実行を行って先にコミットした場合、`SELECT ... FOR KEY SHARE` を実行したトランザクションは失敗し、`OC000` レスポンスが返されます。非キー列に対する同時 `UPDATE` は競合しません。

Aurora DSQL は `NO KEY UPDATE` 句または `FOR SHARE` 句をサポートしていません。ただし、DML は暗黙的に `NO KEY UPDATE` メカニズムを使用します。次のマトリックスは、同じ行にアクセスする 2 つの同時トランザクションが競合する場合をまとめたものです。`X` は、2 つのオペレーションが競合していることを示します。最後にコミットしたトランザクションは失敗し、`OC000` レスポンスが返されます。空白のセルは、両方のトランザクションがコミットできることを示します。


| Operation | `INSERT`、`DELETE`、`UPDATE` (キー列)、または `SELECT ... FOR UPDATE` | `UPDATE` (非キー列のみ) | `SELECT ... FOR KEY SHARE` | 
| --- | --- | --- | --- | 
| INSERT、DELETE、UPDATE (キー列)、または SELECT ... FOR UPDATE | X | X | X | 
| UPDATE (非キー列のみ) | X | X |  | 
| SELECT ... FOR KEY SHARE | X |  |  | 

## トランザクションパフォーマンスを最適化するためのガイドライン
<a name="dsql-perf-guidelines"></a>

パフォーマンスを最適化するには、単一キーまたは小さなキー範囲における高い競合を最小限に抑えます。この目標を達成するには、次のガイドラインを使用して、クラスターキー範囲に更新を分散するようにスキーマを設計します。
+ テーブルのランダムなプライマリキーを選択します。
+ 単一キーでの競合が増加するパターンは避けてください。このアプローチにより、トランザクション量が増えても最適なパフォーマンスが保証されます。