記憶體最佳化的資料表中的交易
以磁碟為基礎之資料表的資料列版本設定 (使用 SNAPSHOT 隔離或 READ_COMMITTED_SNAPSHOT) 會提供某種形式的開放式並行存取控制。 讀取器和寫入器不會封鎖彼此。 在記憶體最佳化的資料表中,寫入器不會封鎖寫入器。 如果在磁碟資料表上使用資料列版本設定,一筆交易會鎖定資料列,而嘗試更新此資料列的並行交易會遭封鎖。 在記憶體最佳化資料表中,不會有任何鎖定。 而是當有兩筆交易嘗試更新相同資料列時,將會發生寫入/寫入衝突 (錯誤 41302)。
記憶體最佳化的資料表允許較高隔離等級 (REPEATABLE READ 和 SERIALIZABLE) 的開放式並行存取控制,這點不同於以磁碟為基礎的資料表。 系統不會鎖定以強制執行隔離等級。 不過,交易結束時將會進行驗證,以確保可重複的讀取或序列化能力假設。 如果違反假設,就會終止交易。 如需詳細資訊,請參閱 Transaction Isolation Levels。
記憶體最佳化資料表的重要交易語意為:
多重版本設定
以快照集為基礎的交易隔離
開放式
衝突偵測
以下章節將說明每個語意。
記憶體最佳化的資料表中的多重版本設定
記憶體最佳化的資料表中的資料列可以有不同的版本。 並行交易可能會存取相同資料列的不同版本。
記憶體最佳化資料表資料是以版本為基礎。 對於任何資料列,可能會有不同的資料列版本在不同的時間點有效。 當 READ_COMMITTED_SNAPSHOT 或 ALLOW_SNAPSHOT_ISOLATION 設為 ON 時,磁碟資料表會維護不同的資料列版本。 記憶體最佳化資料表會維護不同的資料列版本,即使 READ_COMMITTED_SNAPSHOT 和 ALLOW_SNAPSHOT_ISOLATION 設為 OFF 也一樣。 記憶體最佳化的資料表的資料列版本不是在 tempdb 中維護, 而是以內嵌方式維護資料列版本 (當做在記憶體中儲存資料列之記憶體最佳化資料結構的一部分)。
記憶體最佳化的資料表所適用的快照集交易隔離
單一交易中的所有作業都會使用記憶體最佳化資料表的相同交易一致性快照集。 記憶體最佳化的資料表的所有交易隔離都是以快照集為基礎。 例如,使用可序列化隔離等級存取記憶體最佳化的資料表的交易,都將會在相同的交易一致性快照集上執行所有作業。
存取記憶體最佳化的資料表的交易會使用此資料列版本設定來取得資料表中資料列的交易一致性快照集。 交易中任何陳述式所讀取的資料,都是交易開始時就存在之資料的交易一致性版本。 因此,目前交易中的陳述式看不到並行執行之交易所做的任何修改。
記憶體最佳化的資料表的開放式並行存取控制
衝突和失敗的狀況很少見,而且記憶體最佳化資料表的交易會假設與並行交易沒有衝突且作業順利完成。 交易不會對記憶體最佳化資料表進行鎖定或閂鎖以保證交易隔離。 寫入器不會封鎖讀取器。 寫入器不會封鎖寫入器。 但是,交易會在開放式假設之下繼續,在這個假設之下不會與其他交易發生衝突。 不使用鎖定和閂鎖,而且不等候其他交易完成處理相同的資料列可改善效能。
此外,如果某筆交易 (TxA) 讀取的資料列已由另一筆交易 (TxB) 插入或修改,而且正在認可中,它會樂觀地假設該另一筆交易會認可,而不是等候認可發生。 在此情況下,交易 TxA 會相依於交易 TxB 的認可。
衝突偵測、驗證和認可相依性檢查
SQL Server會偵測並行交易之間的衝突,以及隔離等級違規,而且會造成其中一個衝突的交易。 此交易將必須重試。 (如需詳細資訊,請參閱 Memory-Optimized Tables.) 上交易的重試邏輯指導方針
系統會樂觀地假設交易隔離沒有任何衝突和違規。 如果發生的任何衝突可能導致資料庫的不一致或可能違反交易隔離,系統會偵測到這些衝突,並且終止交易。
如果系統偵測到衝突,交易將會終止,而且用戶端必須重試。
下表摘要說明存取記憶體最佳化資料表之交易的錯誤狀況。
存取記憶體最佳化的資料表之交易的錯誤狀況。
錯誤 | 狀況 |
---|---|
寫入衝突。 嘗試更新交易開始之後已更新的記錄。 | 針對並行交易已更新或刪除的資料列進行 UPDATE 或 DELETE 作業。 |
可重複的讀取驗證失敗。 | 交易所讀取的資料列從交易開始就已經變更 (更新或刪除)。 可重複的讀取驗證通常是在使用 REPEATABLE READ 和 SERIALIZABLE 交易隔離等級時進行。 |
可序列化的驗證失敗。 | 從交易開始,就已經在交易中其中一個掃描範圍內插入新的 (虛設) 資料列。 原本在交易開始之前如果資料庫已經認可資料列,交易就已經看得到此資料列。 SERIALIZABLE 驗證通常是在使用 SERIALIZABLE 隔離及驗證 PRIMARY KEY 條件約束時進行。 |
認可相依性失敗。 | 此交易相依於另一筆交易,而後者認可失敗,原因是因為此資料表中的其中一個失敗狀況、發生記憶體不足的情況,或是未能認可到交易記錄。 讀取/寫入交易和唯讀交易都會發生這種失敗狀況。 |
交易存留期間
上表所提及的失敗可能會發生在交易期間的不同時間點。 下圖說明存取記憶體最佳化的資料表的交易階段。
存取記憶體優化資料表之交易的存留期。
正常處理
在此階段中,會執行使用者發行的 Transact-SQL 語句。 從資料表讀取資料列,而且新的資料列版本會寫入資料庫。 此交易會與所有其他並行交易隔離。 此交易會使用從交易開始就存在的記憶體最佳化資料表快照集。
其他交易還看不到這個交易階段的資料表寫入,但是有一個例外狀況:其他交易中的更新和刪除作業可看到資料列更新和刪除,以便偵測寫入衝突。
如果更新或刪除作業從交易的邏輯開始之後就看到資料列已更新或刪除,作業會失敗並出現錯誤 41302。 錯誤 41302 的訊息為:「目前交易嘗試更新自從此交易啟動以來已經更新的資料表 X 記錄。 交易已中止。」
此錯誤會終止交易 (即便 XACT_ABORT 為 OFF),這表示交易將在使用者工作階段結束時回復。 無法認可注定失敗的交易,且僅支援不寫入記錄及不存取記憶體最佳化資料表的讀取作業。
認可相依性
在正常處理期間,交易可讀取其他交易在驗證或認可階段寫入但是尚未認可的資料列。 這些資料列是可見的,因為在驗證階段開始就已經指派交易的邏輯結束時間。
如果交易讀取這類未認可的資料列,它將會相依於該筆交易的認可。 這有兩個主要的含意:
交易在它所相依的交易認可之前無法認可。 換句話說,除非所有相依項目都已清除,否則它無法進入認可階段。
此外,除非所有相依項目都已清除,否則結果集不會傳回給用戶端。 這樣可防止用戶端觀察未認可的資料。
如果有任何相依交易無法認可,就表示發生認可相依性失敗。 這表示交易將無法認可,並且出現錯誤 41301 (「目前交易具有相依性的先前交易已經中止,而且目前交易無法再認可。」)。
驗證階段
在驗證階段,系統會驗證要求的交易隔離等級所需的假設在交易的邏輯開始和邏輯結束之間是否成立。
在驗證階段開始,系統會指派邏輯結束時間給交易。 其他交易會在邏輯結束時間看到資料庫中寫入的資料列版本。 如需詳細資訊,請參閱 認可相依性。
可重複的讀取驗證
如果交易的隔離等級是 REPEATABLE READ 或 SERIALIZABLE,或者資料表是在 REPEATABLE READ 或 SERIALIZABLE 隔離下存取 (,如需詳細資訊,請參閱 交易隔離等級 中個別作業) 的隔離一節,系統會驗證讀取是否可重複。 這表示,它會驗證交易所讀取的資料列版本在交易的邏輯結束時間依然是有效的資料列版本。
如果有任何資料列已更新或變更,交易就無法認可而且會出現錯誤 41305 (「目前交易無法認可,因為可重複的讀取驗證失敗。」)。
如果在插入、更新或刪除作業之後及交易認可之前卸除資料表,也會發生這個錯誤。 這只適用於原生編譯預存程序中的插入、更新或刪除作業。 透過解譯的 Transact-SQL 執行的這類寫入作業會導致 DROP TABLE 語句封鎖並等候交易認可。
可序列化的驗證
可序列化的驗證會在兩個情況下執行:
如果交易的隔離等級為 SERIALIZABLE 或是在 SERIALIZABLE 隔離之下存取資料表。
如果將資料列插入唯一的索引中,例如為 PRIMARY KEY 條件約束建立的索引。 系統會驗證並未同時插入有相同索引鍵的資料列。
系統會驗證沒有任何虛設項目列已寫入資料庫。 系統會評估交易所執行的讀取作業,以判斷在這些讀取作業的掃描範圍內並未插入任何新的資料列。
在唯一的索引中插入索引鍵包含了隱含的讀取作業,以判斷該索引鍵不是重複項目。 唯一索引的可序列化驗證可確保萬一兩筆交易同時插入相同的索引鍵時,這些索引不能有重複。
如果偵測到虛設項目列,交易就無法認可而且會出現錯誤 41325 (「目前交易無法認可,因為可序列化的驗證失敗。」)。
認可處理
如果驗證成功,而且所有交易相依項目都已清除,則交易會進入認可處理階段。 在這個階段,持久性資料表的變更會寫入記錄中,而且記錄會寫入磁碟,以確保持久性。 一旦交易的記錄檔記錄寫入磁碟後,控制權就會傳回給用戶端。
系統會清除此交易的所有認可相依項目,而正在等候此交易認可的所有交易都可以繼續。
限制
記憶體最佳化的資料表不支援跨資料庫的交易。 存取記憶體最佳化的資料表的每一筆交易都無法存取一個以上的資料庫,除非是 tempdb 的讀寫存取以及 master 系統資料庫的唯讀存取。
記憶體最佳化的資料表不支援分散式交易。 以 BEGIN DISTRIBUTED TRANSACTION 啟動的分散式交易無法存取記憶體最佳化的資料表。
記憶體最佳化資料表不支援鎖定。 記憶體最佳化的資料表不支援透過鎖定提示的明確鎖定 (例如 TABLOCK、XLOCK 和 ROWLOCK)。