

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Amazon QLDB 並行模型
<a name="concurrency"></a>

**重要**  
支援終止通知：現有客戶將可以使用 Amazon QLDB，直到 07/31/2025 的支援結束為止。如需詳細資訊，請參閱[將 Amazon QLDB Ledger 遷移至 Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

Amazon QLDB 旨在解決高效能線上交易處理 (OLTP) 工作負載的需求。QLDB 支援類似 SQL 的查詢功能，並提供完整的 ACID 交易。此外，QLDB 資料項目是文件，可提供結構描述彈性和直覺式資料建模。透過核心日誌，您可以使用 QLDB 來存取資料所有變更的完整且可驗證歷史記錄，並視需要將一致交易串流至其他資料服務。

**Topics**
+ [樂觀並行控制](#concurrency.occ)
+ [使用索引來避免完整資料表掃描](#concurrency.indexes)
+ [插入 OCC 衝突](#concurrency.inserts)
+ [使交易具有等冪性](#concurrency.idempotent)
+ [編輯 OCC 衝突](#concurrency.redaction)
+ [管理並行工作階段](#concurrency.sessions)

## 樂觀並行控制
<a name="concurrency.occ"></a>

在 QLDB 中，使用*樂觀並行控制 (OCC) 實作並行控制*。OCC 的運作原理是，多個交易可以經常完成，而不會互相干擾。

使用 OCC，QLDB 中的交易不會取得資料庫資源的鎖定，並以完全可序列化的隔離操作。QLDB 會以序列方式執行並行交易，因此會產生與這些交易以序列方式啟動相同的效果。

在遞交之前，每個交易都會執行驗證檢查，以確保沒有其他遞交的交易修改其存取的資料。如果此檢查顯示有衝突的修改或資料變更的狀態，遞交交易會遭到拒絕。不過，交易可以重新啟動。

當交易寫入至 QLDB 時，由 QLDB 本身實作 OCC 模型的驗證檢查。如果交易因為 OCC 驗證階段失敗而無法寫入日誌，QLDB 會將 傳回`OccConflictException`應用程式層。應用程式軟體負責確保交易重新啟動。應用程式應中止拒絕的交易，然後從頭開始重試整個交易。

若要了解 QLDB 驅動程式如何處理和重試 OCC 衝突和其他暫時性例外狀況，請參閱 [了解 Amazon QLDB 中驅動程式的重試政策](driver-retry-policy.md)。

## 使用索引來避免完整資料表掃描
<a name="concurrency.indexes"></a>

在 QLDB 中，每個 PartiQL 陳述式 （包括每個`SELECT`查詢） 都會在交易中處理，並受到[交易逾時限制](limits.md#limits.fixed)。

最佳實務是，您應該使用`WHERE`述詞子句來執行陳述式，該子句會篩選索引欄位或文件 ID。QLDB 需要索引欄位上的*等式*運算子，才能有效率地查詢文件；例如， `WHERE indexedField = 123`或 `WHERE indexedField IN (456, 789)`。

如果沒有此索引查詢，QLDB 讀取文件時需要執行*完整資料表掃描*。這可能會導致查詢延遲和交易逾時，也會增加 OCC 與競爭交易衝突的機會。

例如，請考慮名為 `Vehicle` 的資料表，該資料表僅在 `VIN` 欄位上有索引。它包含下列文件。


****  

| VIN | Make | 模型 | 顏色 | 
| --- | --- | --- | --- | 
| "1N4AL11D75C109151" | "Audi" | "A5" | "Silver" | 
| "KM8SRDHF6EU074761" | "Tesla" | "Model S" | "Blue" | 
| "3HGGK5G53FM761765" | "Ducati" | "Monster 1200" | "Yellow" | 
| "1HVBBAANXWH544237" | "Ford" | "F 150" | "Black" | 
| "1C4RJFAG0FC625797" | "Mercedes" | "CLK 350" | "White" | 

兩個名為 Alice 和 Bob 的並行使用者正在分類帳中使用相同的資料表。他們想要更新兩個不同的文件，如下所示。

Alice：

```
UPDATE Vehicle AS v
SET v.Color = 'Blue'
WHERE v.VIN = '1N4AL11D75C109151'
```

Bob：

```
UPDATE Vehicle AS v
SET v.Color = 'Red'
WHERE v.Make = 'Tesla' AND v.Model = 'Model S'
```

假設 Alice 和 Bob 同時開始交易。Alice 的`UPDATE`陳述式會對 `VIN` 欄位執行索引查詢，因此只需要讀取該文件。Alice 會先完成並成功遞交她的交易。

Bob 的陳述式會篩選非索引欄位，因此會執行資料表掃描並遇到 `OccConflictException`。這是因為 Alice 的遞交交易修改了 Bob 陳述式正在存取的資料，其中包括資料表中的每個文件，而不只是 Bob 正在更新的文件。

## 插入 OCC 衝突
<a name="concurrency.inserts"></a>

OCC 衝突可以包含新插入的文件，而不只是先前存在的文件。請考慮下圖，其中兩個並行使用者 (Alice 和 Bob) 正在分類帳中使用相同的資料表。他們都只想在述詞值尚不存在的情況下插入新文件。

![\[Amazon QLDB 樂觀並行控制 (OCC) 圖表顯示兩個並行使用者之間衝突例外的範例。\]](http://docs.aws.amazon.com/zh_tw/qldb/latest/developerguide/images/occ-example.png)


在此範例中，Alice 和 Bob 在單一交易中執行下列 `SELECT`和 `INSERT`陳述式。只有在`INSERT`陳述式沒有傳回結果時，他們的應用程式才會執行`SELECT`陳述式。

```
SELECT * FROM Vehicle v WHERE v.VIN = 'ABCDE12345EXAMPLE'
```

```
INSERT INTO Vehicle VALUE
{
    'VIN' : 'ABCDE12345EXAMPLE',
    'Type' : 'Wagon',
    'Year' : 2019,
    'Make' : 'Subaru',
    'Model' : 'Outback',
    'Color' : 'Gray'
}
```

假設 Alice 和 Bob 同時開始交易。這兩個`SELECT`查詢都不會傳回具有 `VIN`的現有文件`ABCDE12345EXAMPLE`。因此，他們的應用程式會繼續進行`INSERT`陳述式。

Alice 會先完成並成功遞交她的交易。然後，Bob 嘗試遞交他的交易，但 QLDB 拒絕它並擲回 `OccConflictException`。這是因為 Alice 的遞交交易修改了 Bob `SELECT`查詢的結果集，而 OCC 在遞交 Bob 的交易之前偵測到此衝突。

此交易範例需要`SELECT`查詢，才能[成為等](#concurrency.idempotent)冪。然後，Bob 可以從頭開始重試他的整個交易。但是他的下一個`SELECT`查詢會傳回 Alice 插入的文件，因此 Bob 的應用程式不會執行 `INSERT`。

## 使交易具有等冪性
<a name="concurrency.idempotent"></a>

[上一節](#concurrency.inserts)中的插入交易也是*等*冪交易的範例。換言之，多次執行相同的交易會產生相同的結果。如果 Bob 在未先檢查特定 `VIN` 是否存在`INSERT`的情況下執行 ，則資料表最終可能會顯示具有重複`VIN`值的文件。

除了 OCC 衝突之外，請考慮其他重試案例。例如，QLDB 可能會在伺服器端成功遞交交易，但用戶端在等待回應時逾時。最佳實務是，讓您的寫入交易具有等冪性，以避免並行或重試時發生任何非預期的副作用。

## 編輯 OCC 衝突
<a name="concurrency.redaction"></a>

QLDB 可防止同時[修訂相同日誌區塊](working.redaction.md)上的修訂。請考慮兩個並行使用者 (Alice 和 Bob) 想要修訂兩個在分類帳中相同區塊上遞交的不同文件修訂的範例。首先，Alice 會執行`REDACT_REVISION`預存程序來請求修訂一個修訂，如下所示。

```
EXEC REDACT_REVISION `{strandId:"JdxjkR9bSYB5jMHWcI464T", sequenceNo:17}`, '5PLf9SXwndd63lPaSIa0O6', 'ADR2Ll1fGsU4Jr4EqTdnQF'
```

然後，當 Alice 的請求仍在處理中時，Bob 請求修訂另一個修訂，如下所示。

```
EXEC REDACT_REVISION `{strandId:"JdxjkR9bSYB5jMHWcI464T", sequenceNo:17}`, '8F0TPCmdNQ6JTRpiLj2TmW', '05K8zpGYWynDlEOK5afDRc'
```

QLDB 會使用 拒絕 Bob 的請求，`OccConflictException`即使他們嘗試修訂兩個不同的文件修訂。這是因為 Bob 的修訂版與 Alice 正在修訂的修訂版位於相同的區塊。Alice 的請求處理完成後，Bob 就可以重試他的修訂請求。

同樣地，如果兩個並行交易嘗試修訂相同的修訂，則只能處理一個請求。另一個請求在 OCC 衝突例外狀況時失敗，直到編輯完成為止。之後，任何修改相同修訂的請求都會導致錯誤，指出修訂已修訂。

## 管理並行工作階段
<a name="concurrency.sessions"></a>

如果您有使用關聯式資料庫管理系統 (RDBMS) 的經驗，您可能熟悉並行連線限制。QLDB 沒有與傳統 RDBMS 連線相同的概念，因為交易是使用 HTTP 請求和回應訊息執行。

在 QLDB 中，類似概念是*作用中工作階段*。工作階段在概念上類似於使用者登入，它會管理對分類帳提出的資料交易請求的相關資訊。作用中工作階段是主動執行交易的工作階段。它也可以是最近完成交易的工作階段，服務預期它會立即開始另一筆交易。QLDB 支援每個工作階段一個主動執行的交易。

每個分類帳的並行作用中工作階段限制定義於 中[Amazon QLDB 中的配額和限制](limits.md#limits.fixed)。達到此限制後，任何嘗試開始交易的工作階段都會導致錯誤 (`LimitExceededException`)。

如需工作階段生命週期以及 QLDB 驅動程式在執行資料交易時如何處理工作階段的相關資訊，請參閱 [使用驅動程式進行工作階段管理](driver-session-management.md#driver-session-mgmt.lifecycle)。如需使用 QLDB 驅動程式在應用程式中設定工作階段集區的最佳實務，請參閱 *Amazon QLDB 驅動程式建議*[設定 QldbDriver 物件](driver.best-practices.md#driver.best-practices.configuring)中的 。