In-Memory OLTP 為記憶體優化數據表提供完整的持久性。 當變更記憶體最佳化資料表的交易提交時,SQL Server(如同對磁碟資料表所做的一樣)保證變更是永久的(即使在資料庫重新啟動後),前提是基礎儲存空間可供使用。 持久性有兩個主要元件:事務歷史記錄,並將數據變更保存到磁碟上的記憶體。
交易記錄
對磁碟數據表或持久記憶體優化數據表所做的所有變更都會在一或多個事務歷史記錄檔記錄中擷取。 當交易認可時,SQL Server 會將與交易相關聯的記錄檔記錄寫入磁碟,再與交易認可的應用程式或使用者會話通訊。 這可確保交易所做的變更是永久性的。 記憶體優化數據表的事務歷史記錄會與磁碟數據表所使用的相同記錄數據流完全整合。 此整合可讓現有的事務歷史記錄備份、復原和還原作業繼續運作,而不需要任何其他步驟。 不過,由於 In-Memory OLTP 可以大幅增加工作負載的交易輸送量,因此您必須確定已適當地設定事務歷史記錄記憶體來處理增加的 IO 需求。
數據和差異檔案
記憶體優化數據表中的數據會儲存為自由格式的數據列,這些數據列會透過記憶體中的一或多個記憶體內部索引連結。 資料列沒有像基於磁碟的資料表那樣的頁面結構。 當應用程式準備好認可交易時,In-Memory OLTP 會產生交易的記錄檔記錄。 記憶體優化資料表的持久性是使用背景執行緒的資料和差異檔案集合來完成。 數據和差異檔案位於一或多個容器中(使用用於 FILESTREAM 數據的相同機制)。 這些容器會對應至稱為記憶體優化檔案群組的新檔案群組類型。
數據會以嚴格循序的方式寫入這些檔案,以將旋轉媒體的磁碟延遲降到最低。 您可以在不同的磁碟上使用多個容器來分散 I/O 活動。 在不同磁碟上的多個容器中存放數據和差異檔案,當從磁碟上的數據和差異檔案讀取到記憶體時,將會提升復原效能。
應用程式不會直接存取數據和增量檔案。 所有數據讀取和寫入都會使用記憶體內部數據。
數據檔
資料檔案包含來自一個或多個記憶體最佳化資料表的資料列,這些資料表中的資料行由多筆交易在進行 INSERT 或 UPDATE 操作時插入。 例如,一個數據列可以來自記憶體優化數據表 T1,而下一個數據列可以來自記憶體優化數據表 T2。 數據列會依事務歷史記錄中的交易順序附加至數據檔,讓數據存取循序進行。 這使得 I/O 輸送量相比隨機 I/O 提高了一個数量级。 對於記憶體大於 16GB 的計算機,每個數據檔的大小大約為 128 MB,而小於或等於 16GB 的計算機則為 16MB。 數據檔滿后,新交易插入的數據列會儲存在另一個數據檔中。 經過一段時間后,長期記憶體優化數據表的數據列會儲存在多個數據檔中,而每個數據檔都包含來自脫離但連續交易範圍的數據列。 例如,在 (100, 200) 範圍內具有交易認可時間戳的數據檔,具有認可時間戳大於 100 且小於或等於 200 的交易所插入的所有數據列。 提交時間戳是當交易準備好提交時,指派給交易的單調遞增的編號。 每個交易都有唯一的提交時間戳。
刪除或更新資料列時,該資料列不會直接在資料檔案中移除或改變,而是將被刪除的資料列追蹤到另一種類型的檔案:差異檔案。 更新操作會以每一列的刪除和插入操作元組來處理。 這可排除數據檔上的隨機IO。
差異檔案
每個數據檔都會與具有相同交易範圍的差異檔案配對,並追蹤交易範圍中交易插入的已刪除數據列。 此資料和增量檔案稱為檢查點檔案組 (CFP),是分配及解除分配的單位,也是合併操作的單位。 例如,對應於交易範圍(100, 200)的差異檔案將會儲存由該範圍內的交易所插入並刪除的數據列。 和數據檔案一樣,增量檔案是循序存取的。
刪除數據列時,數據列不會從數據檔中移除,但數據列的參考會附加至與插入此數據列的交易範圍相關聯的差異檔案。 由於要刪除的資料列已存在於資料檔中,增量檔案只會儲存參考資訊 {inserting_tx_id, row_id, deleting_tx_id } ,並且遵循發起刪除或更新操作的事務日誌順序。
填入數據和差異檔案
數據與差異檔案會由稱為離線檢查點的背景線程填入。 此執行緒會讀取由已認可交易在記憶體優化表上所產生的交易記錄,並將插入和刪除的行的相關資訊附加至適當的資料與增量檔案。 與磁碟數據表不同,當檢查點完成時,數據/索引頁面會以隨機 I/O 方式清除,而記憶體優化數據表的持久性則是透過連續的背景作業來維持。 會存取多個增量檔案,因為交易可以刪除或更新任何先前交易插入的資料列。 刪除資訊總是會附加在增量檔案的結尾。 例如,具有認可時間戳 600 的交易會插入一個新的數據列,並刪除具有認可時間戳 150、250 和 450 的交易所插入的數據列,如下圖所示。 所有 4 個檔案 I/O 作業(3 個用於已刪除的資料列,1 個用於新插入的資料列),都是對應 delta 檔和資料檔的僅附加作業。
存取數據和增量檔案
發生下列情況時,會存取數據檔案和差異檔案組。
離線檢查點線程 此線程會將插入和刪除附加至記憶體優化數據列,並附加至對應的數據和差異檔案組。
合併操作 此操作會合併一或多個數據和差異檔案對,並建立全新的數據和差異檔案對。
當 SQL Server 重新啟動或資料庫恢復上線的崩潰復原過程期間,記憶體優化的數據會透過數據和差異檔案組填入。 在從對應的資料檔案讀取資料列時,增量檔會作為過濾已刪除列的條件。 由於每個數據和增量檔案組都是獨立的,因此這些檔案會以平行方式載入至記憶體,以減少填入記憶體所需的時間。 將數據載入記憶體後,In-Memory OLTP 引擎會套用檢查點檔案尚未涵蓋的活動事務日誌,以確保記憶體優化的數據完整。
在還原作業期間,會從資料庫備份建立 In-Memory OLTP 檢查點檔案,然後套用一或多個事務歷史記錄備份。 如同損毀復原,In-Memory OLTP 引擎會以平行的方式將數據載入記憶體中,以將復原時間的影響降到最低。
合併資料和差異檔案
記憶體優化資料表的資料會儲存在一或多個資料和增量檔案組中(也稱為檢查點檔案組或 CFP)。 數據檔案會儲存插入的數據列和差異檔案參考已刪除的數據列。 在 OLTP 工作負載執行期間,當 DML 作業更新、插入和刪除資料列時,會建立新的 CFP 來保存新的數據列,並將已刪除數據列的參考附加至差異檔案。
所有先前關閉以及目前有效的 CFP 的元數據會儲存在稱為儲存陣列的內部陣列結構中。 它是一個有固定大小(8,192 個項目)的 CFP 陣列。 儲存陣列中的條目會依照交易範圍排序。 儲存陣列中的 CFP(以及記錄的尾端)代表復原具有記憶體優化的資料表的資料庫所需的所有磁碟上狀態。
隨著時間推移和 DML 作業的進行,CFP 數目增加導致儲存陣列達到容量,這會帶來下列挑戰:
已刪除的數據列。 已刪除的數據列會保留在數據檔中,但在對應的差異檔案中標示為已刪除。 不再需要這些數據列,而且將會從記憶體中移除。 如果已刪除的數據列未從 CFP 中移除,則會不必要地使用空間,讓復原時間變慢。
記憶體陣列已滿。 當記憶體陣列中有 8,000 個專案被配置時(陣列中的 192 個專案會保留給現有的合併,以競爭或允許您執行手動合併),則任何新的 DML 交易都不能在持久的記憶體優化數據表上執行。 只允許檢查點和合併作業使用其餘條目。 這可確保 DML 交易不會填滿陣列,並保留陣列中的某些項目,以合併現有的檔案並回收陣列空間。
儲存陣列操作負荷。 內部進程會搜尋儲存陣列以執行作業,例如尋找差異檔案以新增已刪除資料列的相關資訊。 這些作業的成本隨著項目數目而增加。
為了協助避免這些效率低下,較舊的關閉 CFP 會根據以下所述的合併政策進行合併,將儲存陣列壓縮以表示相同的數據集,減少 CFP 數目。
資料庫中所有長期數據表的記憶體內部大小總計不應超過 250 GB。 假設插入、刪除和更新作業,最多使用 250 GB 記憶體的持久數據表平均需要 500 GB 的儲存空間。 記憶體優化檔案群組需要 4,000 對數據與增量檔案,以支援 500 GB 的儲存空間。
資料庫活動的短期激增可能會導致檢查點操作和合併操作延遲,這會對所需的數據檔和差異檔組合數量有所增加。 為了容納資料庫活動負載的短期激增,存儲系統最多可以配置8,000個數據和差異檔案組,合計最多1TB的存儲空間。 達到該限制時,資料庫上不會允許新的交易,直到檢查點作業趕上為止。 如果記憶體中長期數據表的大小超過 250GB,就有可能達到 8,000 個檔案配對限制。
合併作業將一個或多個相鄰的封閉式 CFP 作為輸入(稱為合併來源),並根據內部定義的合併原則產生一個稱為合併目標的結果 CFP。 來源 CFP 每個差異檔案中的專案會用來篩選對應數據檔中的數據列,以移除不需要的數據列。 來源 CFP 中的其餘數據列會合併成一個目標 CFP。 合併完成後,結果合併目標 CFP 會取代來源 CFP(合併來源)。 合併來源 CFP 在從儲存空間移除之前會經歷過渡階段。
在下列範例中,記憶體優化數據表檔案群組在時間戳 500 中有四個數據和差異檔案組,其中包含先前交易的數據。 例如,第一個數據檔中的數據列會對應至時間戳大於 100 且小於或等於 200 的交易;或者,以 (100, 200) 表示。 第二個和第三個數據檔在考慮標示為已刪除的數據列後,顯示其填充度小於50%。 合併作業會結合這兩個 CFP,並建立新的 CFP,其中包含時間戳大於 200 且小於或等於 400 的交易,也就是這兩個 CFP 的合併範圍。 您會看到另一個 CFP,其範圍是(500,600],並且其交易範圍內(200,400]有非空的差異檔案,這顯示合併操作可以與交易活動同時進行,包括從來源 CFP 中刪除更多的數據列。
背景執行緒會使用合併政策來評估所有已關閉的 CFP,然後為符合資格的 CFP 發起一或多個合併請求。 這些合併要求是由離線檢查點線程處理。 合併原則的評估會定期完成,也會在關閉檢查點時執行。
SQL Server 2014 (12.x) 合併原則
SQL Server 2014 (12.x) 會實作下列合併原則:
如果可以合併 2 個以上的連續 CFP,在考慮已刪除的數據列之後,就會排程合併合併,讓結果數據列可以容納理想大小的 1 個 CFP。 CFP 的理想大小取決於如下:
當計算機記憶體小於或等於 16GB 時,數據檔案為 16MB,差異檔案為 1MB。
如果計算機記憶體大於 16GB,則數據檔為 128MB,差異檔案為 16MB。
如果數據檔超過 256 MB 且超過一半的數據列已刪除,單一 CFP 可以自我合併。 例如,如果單一交易或多個並行交易插入或更新大量數據,數據檔可能會成長超過 128 MB,迫使數據檔成長超過其理想的大小,因為交易無法跨越多個 CFP。
以下是一些顯示在合併原則下將合併的 CFP 的例子:
| 相鄰的 CFP 原始程式檔 (% 完整) | 合併選取 |
|---|---|
| CFP0 (30%), CFP1 (50%), CFP2 (50%), CFP3 (90%) | (CFP0,CFP1) 不會選擇 CFP2,因為它會使產生的數據檔大於 100% 理想的大小。 |
| CFP0 (30%), CFP1 (20%), CFP2 (50%), CFP3 (10%) | (CFP0、CFP1、CFP2)。 從左開始選擇檔案。 不會選擇 CTP3,因為它會使產生的數據檔大於 100% 的理想大小。 |
| CFP0 (80%), CFP1 (30%), CFP2 (10%), CFP3 (40%) | (CFP1、CFP2、CFP3)。 從左側開始選取檔案。 會略過 CFP0,因為如果與 CFP1 結合,產生的數據檔將會大於理想大小的 100%。 |
並非所有具有可用空間的 CFP 都符合合併資格。 例如,如果兩個相鄰的 CFP 是 60 個% 已滿,它們不符合合併條件,因此每個 CFP 都會有 40 個% 儲存空間未使用。 在最壞的情況下,所有 CFP 都會是 50% 完整,記憶體使用率僅為 50%。 雖然已刪除的數據列可能存在於記憶體中,因為 CFP 不符合合併資格,但已刪除的數據列可能已經由記憶體內部垃圾收集從記憶體中移除。 儲存和記憶體的管理與垃圾收集無關。 使用中 CFP 所占用的存儲空間(並非所有 CFP 都在更新中)可能比記憶體中持久性數據表的大小大兩倍。
如有需要,可以藉由呼叫 sys.sp_xtp_merge_checkpoint_files (Transact-SQL)明確執行手動合併。
CFP的生命週期
CPF 會先透過數個狀態進行轉換,然後才能解除分配。 在任何指定時間,CFP 都處於下列其中一個階段:預先建立、建構下、作用中、合併目標、合併來源、備份/HA 所需的來源、轉換至 TOMBSTONE 和 TOMBSTONE。 如需這些階段的描述,請參閱sys.dm_db_xtp_checkpoint_files(Transact-SQL)。
在考慮 CFP 在各種狀態中佔用的存儲空間之後,高耐用性記憶體優化表佔用的整體存儲空間可能會遠超過記憶體中表格大小的2倍。 您可以查詢 DMV sys.dm_db_xtp_checkpoint_files (Transact-SQL), 以列出記憶體優化檔案群組中的所有 CFP,包括其階段。 如果將資料庫設定為完整或大容量日誌恢復模式,將 CFP 從 MERGE SOURCE 狀態轉換至 TOMBSTONE,最後垃圾收集可能會佔用五個檢查點,每個檢查點後面接著事務歷史記錄備份。
您可以手動強制執行檢查點,然後進行日誌備份以加速垃圾回收,但這樣會新增 5 個空白 CFP(5 組資料/差異檔案配對,每個資料檔案的大小為 128MB)。 在生產環境中,作為備份策略一部分的自動檢查點和日誌備份,會自動無縫地將 CFP 在這些階段中轉換,無需任何手動介入。 垃圾收集程式的影響在於,具有記憶體優化數據表的資料庫,相較於記憶體大小,記憶體大小可能會較大。 CFP在記憶體中,其大小最多可以達到永久性記憶體優化數據表的四倍,這並不罕見。