瞭解以資料列版本控制為基礎的隔離等級
資料列版本控制是 SQL Server 中的一般架構,可用於執行下列功能:
在觸發程序中建立 inserted 及 deleted 資料表。經由觸發程序修改過的任何資料列都會被建立版本。這包括啟動觸發程序之陳述式所修改的資料列,以及觸發程序所做的任何資料修改。
支援 Multiple Active Result Sets (MARS)。如果 MARS 工作階段在有現用結果集的情況下,發出資料修改陳述式 (例如 INSERT、UPDATE 或 DELETE),就會為修改陳述式所影響的資料列建立版本。
支援指定 ONLINE 選項的索引作業。
支援以資料列版本控制為基礎的交易隔離等級:
新的讀取認可隔離等級實作方式,其使用資料列版本控制來提供陳述式層級的讀取一致性。
新的隔離等級 (快照集),可以提供交易等級的讀取一致性。
tempdb 資料庫必須要有足夠的空間來供版本存放區使用。當 tempdb 滿了之後,更新作業會停止產生版本,並繼續進行到完成為止,但是讀取作業可能會失敗,因為所需的特定資料列版本已不存在。這會影響到像是觸發程序、MARS 及線上檢索索引之類的作業。如需詳細資訊,請參閱<資料列版本控制資源的使用方式>。
針對讀取認可及快照交易,使用資料列版本控制的方法是兩個步驟的程序:
將 READ_COMMITTED_SNAPSHOT 及 ALLOW_SNAPSHOT_ISOLATION 其中一個或兩個資料庫選項都設為 ON。
在應用程式中設定適當的交易隔離等級:
當 READ_COMMITTED_SNAPSHOT 資料庫選項為 ON,設定讀取認可隔離等級的交易就會使用資料列版本控制。
當 ALLOW_SNAPSHOT_ISOLATION 資料庫選項為 ON,交易就會設定快照隔離等級。
當 READ_COMMITTED_SNAPSHOT 或 ALLOW_SNAPSHOT_ISOLATION 其中一個資料庫選項設為 ON,SQL Server Database Engine 就會指定一個交易序號 (XSN) 給使用資料列版本控制來管理資料的每個交易。交易會在執行 BEGIN TRANSACTION 陳述式時開始。但是交易序號會從 BEGIN TRANSACTION 陳述式之後的第一個讀取或寫入作業開始。每指定一個交易序號,就會累加一個號碼。
當 READ_COMMITTED_SNAPSHOT 或 ALLOW_SNAPSHOT_ISOLATION 其中一個資料庫選項為 ON,就會針對在資料庫中執行的所有資料修改來維護邏輯副本 (版本)。每特定交易修改新的資料列時,Database Engine 的執行個體就會將先前認可的資料列影像檔版本儲存在 tempdb 中。每個版本都會標示執行變更之交易的交易序號。修改過的資料列版本會以連結清單鏈結起來。最新的資料列值一律儲存在目前資料庫中,並鏈結到儲存在 tempdb 中的版本資料列。
[!附註]
若為大型物件 (LOB) 的修改,就只會將變更過的片段複製到 tempdb 中的版本存放區。
資料列版本會被保存夠久的時間,可滿足以資料列版本控制為基礎之隔離等級來執行的交易需求。Database Engine 會追蹤最早的有用交易序號,並定期刪除交易序號低於最早有用交易序號的所有資料列版本。
當兩個資料庫選項都設為 OFF 時,就只會針對由觸發程序或 MARS 工作階段所修改的資料列,或是由 ONLINE (線上) 索引作業所讀取的資料列來建立版本。不再需要那些資料列版本時,就會將其釋出。背景執行緒會定期執行,以移除過時的資料列版本。
[!附註]
若為短期的交易,修改過的資料列版本可能會被快取在緩衝集區中,不會被寫入 tempdb 資料庫的磁碟檔中。如果已建立版本的資料列不需要存在很長的時間,就會直接將它從緩衝集區中卸除,而且不一定會引起 I/O 負擔。
讀取資料時的行為
在以資料列版本控制為基礎之隔離下執行的交易要讀取資料時,讀取作業不會在所讀取的資料上取得共用 (S) 鎖定,因此不會阻礙正在修改資料的交易。此外,隨著所取得的鎖定數量減少,鎖定資源的負擔也會降低。使用資料列版本控制及快照隔離的讀取認可隔離作業,目的就是要提供已建立版本之資料的陳述式層級或交易等級讀取一致性。
所有的查詢,包括在資料列版本控制式隔離等級下執行的交易,都會在編譯和執行期間取得 Sch-S (結構描述穩定性) 鎖定。因此,當並行交易在資料表上保有 Sch-M (結構描述修改) 鎖定時,查詢將會被封鎖。例如,資料定義語言 (DDL) 作業會在修改資料表的結構描述資訊之前先取得 Sch-M 鎖定。查詢交易,包括在資料列版本控制式隔離等級下執行的交易,在嘗試取得 Sch-S 鎖定時都會遭到封鎖。相反地,保有 Sch-S 鎖定的查詢將會封鎖嘗試取得 Sch-M 鎖定的並行交易。如需有關鎖定行為的詳細資訊,請參閱<鎖定相容性 (Database Engine)>。
當使用快照隔離等級的交易開始時,Database Engine 的執行個體會記錄目前所有的使用中交易。當快照交易讀取具有版本鏈結的資料列時,Database Engine 會依循該鏈結,並擷取下列交易序號的資料列:
最接近但小於讀取該資料列之快照交易的序號。
當快照交易開始時,不在使用中交易清單裡的序號。
快照集交易所執行的讀取作業會在快照集交易開始時,擷取已認可之每個資料列的最新版本。這樣可以讓資料快照集在交易期間保持一致,就像交易一開始的資料一樣。
使用資料列版本控制的讀取認可交易運作的方式也相當類似。不同的地方在於,讀取認可交易在選擇資料列版本時,不會使用自己的交易序號。每當有陳述式開始時,讀取認可交易就會讀取針對該 Database Engine 執行個體所發出的最新交易序號。這個交易序號可用來為該陳述式選取正確的資料列版本。這樣可以讓讀取認可交易看到與每個陳述式開始時相同的資料快照。
[!附註]
即使使用資料列版本控制的讀取認可交易可以提供陳述式層級資料的交易一致性檢視,這種類型的交易所產生或存取的資料列版本還是會保留到交易完成為止。
修改資料時的行為
在使用資料列版本控制的讀取認可交易中,會使用封鎖掃描來選取要更新的資料列,在封鎖掃描中,當資料值被讀取時,就會在資料列上進行更新 (U) 鎖定。這與不使用資料列版本控制的讀取認可交易是一樣的。如果資料列不符合更新條件,就會解除該資料列的更新鎖定,並且會鎖定及掃描下一個資料列。
在快照集隔離下執行的交易會使用開放式的方法來修改資料,在修改資料之前,會在資料上取得鎖定,只強制執行條件約束。否則,在修改資料之前,不會在資料上取得鎖定。當資料列符合更新條件,快照交易會確認資料列尚未被快照交易開始之後認可的並行交易所修改。如果資料列已在快照交易外被修改,就會發生更新衝突,並終止快照交易。Database Engine 會處理更新衝突,而且沒有可以停用更新衝突偵測的方法。
[!附註]
當快照交易存取以下任一項時,在快照隔離下執行的更新作業,會在讀取認可隔離之下於內部執行:
具有 FOREIGN KEY 條件約束的資料表。
被另一個資料表的 FOREIGN KEY 條件約束所參考的資料表。
參照多個資料表的索引檢視。
然而,即使有這些條件限制,更新作業仍會繼續確認資料尚未被其他交易所修改。如果資料已被其他交易所修改,快照交易會發生更新衝突,並終止作業。
行為摘要
下表摘要說明使用資料列版本控制之快照隔離與讀取認可隔離之間的差異。
屬性 |
使用資料列版本控制的讀取認可隔離等級 |
快照隔離等級 |
---|---|---|
資料庫選項必須設為 ON,才能啟用必要的支援。 |
READ_COMMITTED_SNAPSHOT |
ALLOW_SNAPSHOT_ISOLATION |
工作階段如何要求特定類型的資料列版本控制。 |
使用預設的讀取認可隔離等級,或是執行 SET TRANSACTION ISOLATION LEVEL 陳述式來指定 READ COMMITTED 隔離等級。您可以在交易開始後完成此作業。 |
需要執行 SET TRANSACTION ISOLATION LEVEL,以在交易開始之前指定 SNAPSHOT 隔離等級。 |
陳述式所讀取的資料版本。 |
在每個陳述式開始之前認可的所有資料。 |
在每個交易開始之前認可的所有資料。 |
如何處理更新。 |
從資料列版本還原成實際的資料,以選取要更新的資料列,並且在所選取的資料列上使用更新鎖定。在所要修改的實際資料列上取得獨佔鎖定。無更新衝突偵測。 |
使用資料列版本來選取要更新的資料列。嘗試在所要修改的實際資料列上取得獨佔鎖定,若該資料已被其他交易所修改,就會發生更新衝突,且快照交易會終止進行。 |
更新衝突偵測。 |
無。 |
整合支援。無法停用。 |