

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

# Aurora MySQL 隔離層級
<a name="AuroraMySQL.Reference.IsolationLevels"></a>

了解 Aurora MySQL 叢集的資料庫執行個體如何實作資料庫的隔離屬性。此主題解釋 Aurora MySQL 預設行為如何在嚴格一致性與高效能之間取得平衡點。您可以根據工作負載的特性，使用此資訊協助您決定何時變更預設設定。

## 寫入器執行個體可用的隔離層級
<a name="AuroraMySQL.Reference.IsolationLevels.writer"></a>

您可以在 Aurora MySQL 資料庫叢集的主要執行個體上使用隔離等級 `REPEATABLE READ`、`READ COMMITTED`、`READ UNCOMMITTED` 和 `SERIALIZABLE`。這些隔離層級在 Aurora MySQL 和 RDS for MySQL 中以同樣的方式運作。

## 讀取器執行個體的 REPEATABLE READ 隔離層級
<a name="AuroraMySQL.Reference.IsolationLevels.reader"></a>

根據預設，設定成唯讀 Aurora 複本的 Aurora MySQL 資料庫執行個體一律使用 `REPEATABLE READ` 隔離層級。這些資料庫執行個體忽略任何 `SET TRANSACTION ISOLATION LEVEL` 陳述式，並繼續使用 `REPEATABLE READ` 隔離層級。

## 讀取器執行個體的 READ COMMITTED 隔離層級
<a name="AuroraMySQL.Reference.IsolationLevels.relaxed"></a>

如果應用程式在主要執行個體上有密集寫入的工作負載，而在 Aurora 複本上有長時間執行的查詢，您可能會感受到嚴重的清除延遲。如果長時間執行的查詢阻礙內部垃圾收集，此即所謂的*清除延遲*。您看見的徵狀是在 `history list length` 命令的輸出中，`SHOW ENGINE INNODB STATUS` 的值很高。您可以在 CloudWatch 中使用 `RollbackSegmentHistoryListLength` 指標監控此值。嚴重的清除延遲會降低次要索引的效率，導致整體查詢效能下降和儲存空間浪費。

如果遇到這種問題，您可以設定 Aurora MySQL 工作階段層級的組態設定 `aurora_read_replica_read_committed`，在 Aurora 複本上使用 `READ COMMITTED` 隔離層級。在交易修改資料表的同時，長時間執行的查詢可能導致速度變慢和浪費空間，套用此設定有助於避免這種情形。

使用此設定前，建議您了解 Aurora MySQL 在 `READ COMMITTED` 隔離情況下的具體行為。Aurora 複本 `READ COMMITTED` 行為符合 ANSI SQL 標準。然而，此隔離不像您所熟悉的 MySQL `READ COMMITTED` 獨特行為那麼嚴格。因此，就同樣的查詢而言，在 Aurora MySQL 僅供讀取複本的 `READ COMMITTED` 情況下，以及在 Aurora MySQL 主要執行個體或 RDS for MySQL 的 `READ COMMITTED` 情況下，您所見的查詢結果可能不同。在某些案例中，例如綜合報告掃描巨大的資料庫，您可以考慮使用 `aurora_read_replica_read_committed` 設定。反之，如果準確性和可重複性很重要，以較短的查詢來產生較小的結果集可避免此情況。

`READ COMMITTED` 隔離層級不適用於在使用寫入轉送功能的 Aurora 全域資料庫中次要叢集內的工作階段。如需寫入轉送的資訊，請參閱 [在 Amazon Aurora 全域資料庫中使用寫入轉送](aurora-global-database-write-forwarding.md)。

### 對讀取器使用 READ COMMITTED
<a name="AuroraMySQL.Reference.IsolationLevels.relaxed.enabling"></a>

若要對 Aurora 複本使用 `READ COMMITTED` 隔離層級，請將 `aurora_read_replica_read_committed` 組態設定為 `ON`。請於連線至特定 Aurora 複本時，在工作階段層級使用此設定。若要這樣做，請執行下列 SQL 命令：

```
set session aurora_read_replica_read_committed = ON;
set session transaction isolation level read committed;
```

您可以暫時使用此組態設定，以執行互動的臨時性一次查詢。您也可以執行報告或資料分析應用程式來善用 `READ COMMITTED` 隔離層級，但對於其他應用程式維持預設設定不變。

啟用 `aurora_read_replica_read_committed` 設定時，請使用 `SET TRANSACTION ISOLATION LEVEL` 命令為適當的交易指定隔離層級。

```
set transaction isolation level read committed;
```

### Aurora 複本上 READ COMMITTED 行為的差異
<a name="AuroraMySQL.Reference.IsolationLevels.relaxed.behavior"></a>

`aurora_read_replica_read_committed` 設定可讓 Aurora 複本使用 `READ COMMITTED` 隔離層級，其一致性行為最適合長時間執行的交易。Aurora 複本上的 `READ COMMITTED` 隔離層級，不像 Aurora 主要執行個體上的隔離那麼嚴格。因此，在 Aurora 複本上，只在您知道查詢能接受可能有某種不一致結果時，才應該啟用此設定。

啟用 `aurora_read_replica_read_committed` 設定時，查詢可能會遇到某種讀取異常狀況。在應用程式碼中，特別需要了解和處理兩種異常。當查詢執行時有另一個交易遞交，此即所謂的*不可重複讀取*。長時間執行的查詢在查詢開始和結束時所見的資料不同。當查詢執行時有其他交易導致現有的列重組，使得查詢讀取一或多列兩次，此即所謂的*幻影讀取*。

幻影讀取可能導致查詢看到不一致的列計數。查詢也可能因為不可重複讀取而傳回不完整或不一致的結果。例如，假設聯結操作所參考的資料表有 SQL 陳述式正在修改，例如 `INSERT` 或 `DELETE`。在此情況下，聯結從一個資料表中讀取的列，可能不是另一個資料表中相應的列。

ANSI SQL 標準在 `READ COMMITTED` 隔離層級下允許這兩種行為。不過，這些行為不同於 MySQL 典型的 `READ COMMITTED` 實作。因此，在啟用 `aurora_read_replica_read_committed` 設定之前，請檢查任何現有的 SQL 程式碼，確認在較寬鬆一致性模式下的運作符合預期。

啟用此設定時，在 `READ COMMITTED` 隔離層級下，列計數和其他結果可能不那麼一致。因此，通常只在執行分析查詢來彙總大量資料，且不需要絕對精準時，您才啟用此設定。如果您沒有這種長時間執行的查詢，也沒有密集寫入的工作負載，可能就不需要 `aurora_read_replica_read_committed` 設定。如果既沒有長時間執行的查詢，也沒有寫入密集的工作負載，就不太可能遭遇歷史記錄清單過長的問題。

**Example 顯示 Aurora 複本上 READ COMMITTED 隔離行為的查詢**  
下列範例顯示 Aurora 複本上的 `READ COMMITTED` 查詢在同時有交易修改相關聯資料表時，如何傳回不可重複的結果。在任何查詢開始前，資料表 `BIG_TABLE` 包含 1 百萬列。查詢執行時有其他資料操作語言 (DML) 陳述式新增、移除或變更列。  
在 `READ COMMITTED` 隔離層級下，Aurora 主要執行個體上的查詢產生可預測的結果。但是，為了替每個長時間執行的查詢自始至終維持一致的讀取檢視，所付出的成本將導致後來垃圾收集的代價更高。  
在 `READ COMMITTED` 隔離層級下，Aurora 複本上的查詢最能將此垃圾收集成本降到最低。根據查詢擷取的列是否為查詢執行當時遞交的交易所新增、移除或重組而定，結果可能不同，而這就是代價。查詢可以考慮這幾列，但並非必要。為了示範，查詢只使用 `COUNT(*)` 函數檢查資料表的列數。  


| 時間 | Aurora 主要執行個體上的 DML 陳述式 | Aurora 主要執行個體上搭配 READ COMMITTED 的查詢 | Aurora 複本上搭配 READ COMMITTED 的查詢 | 
| --- | --- | --- | --- | 
|  T1  |  INSERT INTO big\$1table SELECT \$1 FROM other\$1table LIMIT 1000000; COMMIT;   |  |  | 
|  T2  |  |  Q1: SELECT COUNT(\$1) FROM big\$1table;  |  Q2: SELECT COUNT(\$1) FROM big\$1table;  | 
|  T3  |  INSERT INTO big\$1table (c1, c2) VALUES (1, 'one more row'); COMMIT;   |  |  | 
|  T4  |  |  如果 Q1 現在完成，則結果為 1,000,000。 |  如果 Q2 現在完成，則結果為 1,000,000 或 1,000,001。 | 
|  T5  |  DELETE FROM big\$1table LIMIT 2; COMMIT;   |  |  | 
|  T6  |  |  如果 Q1 現在完成，則結果為 1,000,000。 |  如果 Q2 現在完成，則結果為 1,000,000 或 1,000,001 或 999,999 或 999,998。 | 
|  T7  |  UPDATE big\$1table SET c2 = CONCAT(c2,c2,c2); COMMIT;   |  |  | 
|  T8  |  |  如果 Q1 現在完成，則結果為 1,000,000。 |  如果 Q2 現在完成，則結果為 1,000,000 或 1,000,001 或 999,999，或者，可能是某個更大的數字。 | 
|  T9  |  |  Q3: SELECT COUNT(\$1) FROM big\$1table;  |  Q4: SELECT COUNT(\$1) FROM big\$1table;  | 
|  T10  |  |  如果 Q3 現在完成，則結果為 999,999。 |  如果 Q4 現在完成，則結果為 999,999。 | 
|  T11  |  |  Q5: SELECT COUNT(\$1) FROM parent\$1table p JOIN child\$1table c ON (p.id = c.id) WHERE p.id = 1000;  |  Q6: SELECT COUNT(\$1) FROM parent\$1table p JOIN child\$1table c ON (p.id = c.id) WHERE p.id = 1000;  | 
|  T12  |   INSERT INTO parent\$1table (id, s) VALUES (1000, 'hello'); INSERT INTO child\$1table (id, s) VALUES (1000, 'world'); COMMIT;   |  |  | 
|  T13  |  |  如果 Q5 現在完成，則結果為 0。 |  如果 Q6 現在完成，則結果為 0 或 1。 | 
如果查詢快速完成，在其他任何交易執行 DML 陳述式和遞交之前，結果是在主要執行個體與 Aurora 複本之間是可預測且相同。從第一個查詢開始詳細檢查行為的差異。  
Q1 的結果很容易預測，因為主要執行個體上的 `READ COMMITTED` 使用類似於 `REPEATABLE READ` 隔離層級的強大一致性模式。  
隨著查詢執行當時交易是遞交什麼而定，Q2 的結果可能不同。例如，假設查詢執行當時，有其他交易執行 DML 陳述式並遞交。在此情況下，Aurora 複本上搭配 `READ COMMITTED` 隔離層級的查詢可能考量或不考量變更。列計數不能像在 `REPEATABLE READ` 隔離層級下那樣預測。也不像在主要執行個體或 RDS for MySQL 執行個體上於 `READ COMMITTED` 隔離層級下執行的查詢那麼可預測。  
T7 上的 `UPDATE` 陳述式實際上不變更資料表的列數。不過，此陳述式能夠變更可變長度欄的長度，導致列在內部重組。長時間執行的 `READ COMMITTED` 交易可能看到某一列的舊版本，而後來在相同查詢內，可能又看到那同一列的新版本。該查詢也可以同時略過此列的新舊版本，因此列數可能與預期不同。  
Q5 和 Q6 的結果可能完全相同或稍微不同。Aurora 複本上在 `READ COMMITTED` 下的查詢 Q6 能夠看到 (但不必一定看到) 查詢執行當時遞交的新列。也可能看到只在一個資料表而不在另一個資料表中的列。如果聯結查詢在兩個資料表中找不到相符一列，則傳回計數為零。如果查詢在 `PARENT_TABLE` 和 `CHILD_TABLE` 中都找到新列，查詢傳回計數為 1。在長時間執行的查詢中，可能間隔很久才查閱聯結的資料表。  
這些行為差異取決於交易遞交的時間，以及查詢何時處理基礎資料表列。因此，在耗費數分鐘或數小時，且在同時處理 OLTP 交易的 Aurora 叢集上所執行的報告查詢中，最可能看到這些差異。Aurora 複本上的 `READ COMMITTED` 隔離層級最有益於這幾種混合工作負載。