内存优化表的持久性

适用于:SQL Server

内存中 OLTP 为内存优化表提供完整持续性。 更改内存优化表的事务提交时,SQL Server(与基于磁盘的表一样),保证更改是永久性的(在数据库重启后保留),前提是基础存储可用。 持续性有两个重要方面:事务日志记录和在磁盘存储上持久保存数据更改。

有关耐久表的任何大小限制的详细信息,请参阅 内存优化表的内存要求估算

事务日志

对基于磁盘的表或持久的内存优化表所做的所有更改均捕获在一个或多个事务日志记录中。 提交事务时,SQL Server 将与事务关联的日志记录写入磁盘,然后再通知应用程序或用户会话事务已提交。 这样可确保事务所做的更改是持久的。 内存优化表的事务日志与基于磁盘的表使用的相同日志流完全集成。 此集成允许现有的事务日志备份、恢复和还原作继续工作,而无需执行任何额外的步骤。 但是,由于 In-Memory OLTP 可能会显著增加工作负荷的事务吞吐量,因此日志 IO 可能会成为性能瓶颈。 若要保持此增长的吞吐量,请确保日志 IO 子系统可以处理增加的负载。

数据和增量文件

内存优化表中的数据在内存中堆数据结构中存储为自由格式的数据行,它们通过内存中的一个或多个索引链接起来。 这些数据行没有基于磁盘的表所使用的页面结构。 为了保持长期的持久性并允许截断事务日志,内存优化表中的操作存留在一组数据和差异文件中。 这些文件是使用异步后台进程基于事务日志而生成的。 数据文件和差异文件位于一个或多个容器中(使用 FILESTREAM 数据所用的机制)。 这些容器是内存优化文件组的一部分。

按严格顺序向这些文件写入数据,这样可将旋转介质的磁盘延迟降至最低。 可使用不同驱动器上的多个容器分散 I/O 活动。 将数据从磁盘上的数据和增量文件读取到内存时,不同磁盘上多个容器中的数据和增量文件会增加数据库还原/恢复性能。

用户事务不直接访问数据和增量文件。 所有数据读取和写入均使用内存中数据结构。

数据文件

数据文件将包含一个或多个内存优化表中作为 INSERT 或 UPDATE 操作的一部分由多个事务插入的行。 例如,一行可以来自内存优化表 T1,而下一行可以来自内存优化表 T2。 这些行按事务日志中事务的顺序追加到数据文件,使数据访问顺序进行。 这将使 I/O 吞吐量比随机 I/O 提高一个数量级。

一旦数据文件已满,新事务插入的行就存储于其他数据文件中。 随着时间的推移,持久内存优化表中的行存储在多个数据文件中,每个包含行的数据文件构成了不连续但连续的事务范围。 例如,事务提交时间戳范围为 (100, 200) 的数据文件包含由提交时间戳大于 100 并小于等于 200 的事务插入的所有行。 提交时间戳是一个单调递增的序列号,当事务准备提交时分配给它。 每个事务都具有唯一的提交时间戳。

当删除或更新行时,该行在数据文件中不会被直接移除或更改,已删除的行会被跟踪到另一种文件类型:用于记录变化的增量文件。 更新操作以针对每一行的删除和插入操作的元组形式进行处理。 这将消除数据文件上的随机 IO。

大小:在内存大于 16 GB 的计算机中,每个数据文件的大小约为 128 MB;在内存小于或等于 16 GB 的计算机中,其大小约为 16 MB。 如果它认为存储子系统的速度不够快,则可在 SQL Server 2016 (13.x) SQL Server 中使用大型检查点模式。 在大型检查点模式下,数据文件的大小将调整为 1 GB。 这将实现存储子系统更高的效率,从而拥有高吞吐量的工作负荷。

增量文件

每个数据文件都与一个差异文件配对,后者的事务范围相同,并跟踪事务范围中的事务插入的已删除行。 此数据文件和增量数据文件称为检查点文件对(CFP),它是分配和释放的单元以及合并操作的单元。 例如,事务范围(100到200)对应的增量文件存储了在范围(100到200)内事务插入的已删除行。 与数据文件一样,差异文件是顺序访问的。

删除行时,该行不会从数据文件中删除,但对行的引用将追加到与插入此数据行的事务范围关联的增量文件。 由于要删除的行已存在于数据文件中,因此差异文件仅存储引用信息 {inserting_tx_id, row_id, deleting_tx_id} ,并且遵循原始删除或更新操作的事务日志顺序。

大小:在内存大于 16 GB 的计算机中,每个数据文件的大小约为 16 MB;在内存小于或等于 16 GB 的计算机中,其大小约为 1 MB。 如果它认为存储子系统的速度不够快,则启动 SQL Server 2016 (13.x) SQL Server 可使用大型检查点模式。 在大型检查点模式下,差异文件的大小将调整为 128 MB。

填充数据和增量文件

基于已提交事务在内存优化表上生成的事务日志记录填充数据和差异文件,并且将与已插入行和已删除行有关的信息追加到相应的数据和差异文件中。 与基于磁盘的表(在此类表中,在检查点操作完成时使用随机 I/O 刷新数据/索引页)不同,内存优化表的持续性是连续的后台操作。 由于事务可以删除或更新由任何先前的事务插入的任何行,因此将对多个差异文件进行访问。 删除信息始终追加到差异文件的末尾。 例如,提交时间戳为 600 的事务插入一个新行,并删除提交时间戳为 150、250 和 450 的事务插入的行,如下图所示。 所有四个文件I/O操作(删除行对应有三个操作,新增行对应有一个操作),都是对相应的增量文件和数据文件进行仅追加操作。

内存优化表的读取日志记录的屏幕截图。

访问数据和增量文件

发生以下事件时,将访问数据文件和增量文件对。

离线检查点工人

此线程将对内存优化数据行执行的插入和删除追加到对应的数据和差异文件对。 SQL Server 2014 (12.x) 具有一个脱机检查点工作者。 SQL Server 2016 (13.x)和更高版本具有多个检查点工作线程。

合并操作

此操作会合并一个或多个数据和差异文件对,并创建新的数据和差异文件对。

在崩溃恢复期间

当 SQL Server 重新启动或数据库重新联机时,将使用数据和差异文件对来填充内存优化数据。 从对应的数据文件读取行时,差异文件充当用于已删除行的筛选器。 由于每个数据和差异文件对均独立,因此并行加载这些文件以缩短将数据填充到内存中所用的时间。 将数据加载到内存中后,In-Memory OLTP 引擎会应用检查点文件尚未涵盖的活动事务日志记录,以便内存优化数据完成。

还原操作期间

从数据库备份创建内存中 OLTP 检查点文件,然后应用一个或多个事务日志备份。 与故障恢复一样,In-Memory OLTP 引擎并行将数据加载到内存中,以最大程度地减少对恢复时间的影响。

合并数据和增量文件

内存优化表的数据存储于一个或多个数据和差异文件对(也称作检查点文件对,即 CFP)中。 数据文件存储插入的行,而差异文件引用删除的行。 在 OLTP 工作负荷执行期间,在 DML 操作更新、插入和删除行时,将创建新 CFP 以便持久保存新行,并将对已删除行的引用附加到差异文件中。

随着 DML 操作的进行,数据和增量文件的数量不断增加,导致磁盘空间使用量和恢复时间均增加。

为了避免这些低效情况,本文后面描述的合并策略将合并较旧的封闭数据和增量文件,从而精简存储阵列以表示相同的数据集,减少文件数量。

合并操作将一个或多个相邻的封闭的检查点文件对(CFP)作为输入,这些文件对是由数据文件和增量文件(称为合并源)组成的,并基于内部定义的合并策略生成一个结果 CFP,称为合并目标。 源 CFP 的每个增量文件中的条目用于筛选相应数据文件中的行,以删除不需要的数据行。 源 CFP 中的其余行将合并到一个目标 CFP 中。 合并完成后,生成的合并目标 CFP 将替换源 CFP(合并源)。 合并源 CFP 在从存储中删除之前会经历过渡阶段。

在以下示例中,内存优化表文件组在时间戳 500 处具有四个数据和增量文件对,其中包含以前事务中的数据。 例如,第一个数据文件中的行对应于时间戳大于 100 且小于等于 200 的事务,或者表示为 (100,200]。 考虑到标为已删除的行后,将第二个和第三个数据文件显示为完整程度小于 50%。 合并操作合并这两个 CFP 并且创建一个新 CFP,它包含时间戳大于 200 且小于等于 400 的事务,这是这两个 CFP 的合并后的范围。 您将看到另一个具有范围 (500, 600] 的 CFP,并且用于事务范围 (200, 400] 的非空差异文件显示,可与事务性活动(包括从源 CFP 删除更多行)同时完成合并操作。

图表显示内存优化的表文件组。

后台线程使用合并策略计算所有关闭的 CFP,然后启动一个或多个合并请求以便验证 CFP 的资格。 这些合并请求由脱机检查点线程处理。 将定期进行对合并策略的评估,并且在关闭检查点时也会进行评估。

SQL Server 合并策略

SQL Server 实现以下合并策略:

  • 如果在考虑已删除的行后可以合并两个或多个连续 CFP,则会计划合并合并,以便生成的行可以容纳目标大小的一个 CFP。 数据和增量文件的目标数据大小对应于原始尺寸设定,如前所述。

  • 如果数据文件超过目标大小的两倍,并且删除的行超过一半,则单个 CFP 可自行合并。 例如,如果单个事务或多个并发事务插入或更新大量数据,则数据文件可能会超过目标大小增长,因为事务不能跨越多个 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)。 从左侧开始选择文件。

CFP3 未选择,因为它使生成的数据文件大于 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 都在更新)可能达到内存中持久表大小的两倍。

CFP 的生命周期

CFP 要先经过若干状态才可被释放。 需要生成数据库检查点和日志备份,以通过这些阶段转换这些文件,并最终清理不再需要的文件。 请参阅 sys.dm_db_xtp_checkpoint_files 以了解有关这些阶段的说明。

你可以在日志备份后手动强制生成检查点,以便加快垃圾回收。 在生产场景中,作为备份策略的一部分所进行的自动检查点和日志备份无缝地使CFP过渡这些阶段,而无需任何手动干预。 垃圾回收过程的影响是,具有内存优化表的数据库的存储大小可能会比其在内存中的大小更大。 如果未发生检查点和日志备份,检查点文件的磁盘占用量会继续增长。