缓冲区管理

SQL Server 数据库的主要用途是存储和检索数据,因此密集型磁盘 I/O 是数据库引擎的一大特点。此外,完成磁盘 I/O 操作要消耗许多资源并且耗时较长,所以 SQL Server 侧重于提高 I/O 效率。缓冲区管理是实现高效 I/O 操作的关键环节。缓冲区管理组件由下列两种机制组成:用于访问及更新数据库页的缓冲区管理器和用于减少数据库文件 I/O 的缓冲区高速缓存(又称为“缓冲池”)。

缓冲区管理的工作原理

一个缓冲区就是一个 8KB 大小的内存页,其大小与一个数据页或索引页相当。因此,缓冲区高速缓存被划分为多个 8KB 页。缓冲区管理器负责将数据页或索引页从数据库磁盘文件读入缓冲区高速缓存中,并将修改后的页写回磁盘。缓冲区缓存中会保留一页,直到缓冲区管理器需要该缓冲区读入更多数据。数据只有在被修改后才重新写入磁盘。在将缓冲区高速缓存中的数据写回磁盘之前,可对其进行多次修改。有关详细信息,请参阅 读取页写入页

当 SQL Server 启动时,它根据许多参数(例如,系统中的物理内存容量、已配置的服务器最大线程数以及各种引导参数)计算出缓冲区高速缓存的虚拟地址空间大小。SQL Server 将为缓冲区高速缓存保留计算后得出的进程虚拟地址空间(称为“内存目标”),但它仅获取(提交)当前负荷所需的物理内存量。您可以查询 sys.dm_os_sys_info 目录视图中的 bpool_commit_targetbpool_committed 列,分别返回保留为内存目标的页数以及缓冲区高速缓存中当前提交的页数。

SQL Server 启动与缓冲区高速缓存获得其内存目标之间的间隔称为“增长期”。在此期间,读取请求将根据需要填充缓冲区。例如,单页读取请求将填充一个缓冲区页。也就是说,增长期取决于客户端请求的数量和类型。通过将单页读取请求转换为对齐的八页请求加快增长。这样可更快地完成增长,尤其是那些内存容量很大的机器。

因为缓冲区管理器将多数内存用于 SQL Server 进程,所以它会与内存管理器协作以使其他组件能使用其缓冲区。缓冲区管理器主要与下列组件交互:

  • 资源管理器。此交互用于控制内存的整体使用情况以及 32 位平台中的地址空间使用情况。

  • 数据库管理器和 SQL Server 操作系统 (SQLOS)。此交互用于低级文件 I/O 操作。

  • 日志管理器。此交互用于预写日志记录。

支持的功能

缓冲区管理器支持以下功能:

  • 缓冲区管理器可识别非一致性内存访问 (NUMA)。缓冲区高速缓存页将跨硬件 NUMA 节点进行分布,它允许线程访问分配到本地 NUMA 节点上的缓冲区页,而不是从外部内存访问。有关详细信息,请参阅 SQL Server 如何支持 NUMA。若要了解使用 NUMA 时如何分配缓冲区高速缓存中的内存页,请参阅使用 NUMA 扩展和收缩缓冲池

  • 缓冲区管理器支持热添加内存,用户无需重新启动服务器即可添加物理内存。有关详细信息,请参阅 热添加内存

  • 启用 AWE 时,缓冲区管理器在 Microsoft Windows XP 32 位平台和 Windows 2003 32 位平台上支持动态内存分配。动态内存分配允许数据库引擎有效获取和释放缓冲区高速缓存中的内存以支持当前工作负荷。有关详细信息,请参阅动态内存管理

  • 缓冲区管理器在 64 位平台上支持大型页。页大小因 Windows 版本不同而异。有关详细信息,请参阅 Windows 文档。

  • 缓冲区管理器提供通过动态管理视图显示的其他诊断信息。您可以使用这些视图来监视 SQL Server 特有的各种操作系统资源。例如,您可以使用 sys.dm_os_buffer_descriptors 视图来监视缓冲区高速缓存中的页。有关详细信息,请参阅 与 SQL Server 操作系统有关的动态管理视图和函数 (Transact-SQL)

磁盘 I/O

缓冲区管理器仅对数据库执行读写操作。其他文件和数据库操作(如打开、关闭、扩展和收缩)则由数据库管理器和文件管理器组件执行。

缓冲区管理器的磁盘 I/O 操作具有以下特点:

  • 所有 I/O 操作均异步执行。这样,在后台进行 I/O 操作的同时,即可调用线程继续处理。

  • 所有 I/O 操作均在调用线程中发出,除非使用 affinity I/O 选项。Affinity I/O mask 选项将 SQL Server 磁盘 I/O 绑定到指定的 CPU 子集。在高端 SQL Server 联机事务处理 (OLTP) 环境中,此扩展可以提高 SQL Server 线程执行 I/O 的性能。

  • 可通过散播-聚集 I/O 实现多页 I/O,散播-聚集 I/O 允许数据传入或传出非连续内存区域。这意味着 SQL Server 可以快速填充或刷新缓冲区高速缓存,同时避免多个物理 I/O 请求。

长时 I/O 请求

缓冲区管理器报告任何经过 15 秒或更长时间仍未完成的 I/O 请求。这可以帮助系统管理员区分 SQL Server 问题和 I/O 子系统问题。将报告错误消息 833 并且该消息在 SQL Server 错误日志中显示如下:

SQL Server 已 %d 次遇到了针对数据库 [%ls] (%d) 中文件 [%ls] 的、所需完成时间超过 %d 秒的 I/O 请求。OS 文件句柄是 0x%p。最新的长时间 I/O 操作的偏移量是: %#016I64x。

长时 I/O 可以是读或写,不过当前消息并未指明。长时 I/O 消息是警告而不是错误。它们不指示 SQL Server 存在问题。报告这些消息是为了帮助系统管理员更快地找到 SQL Server 响应缓慢的原因,并找出 SQL Server 无法控制的问题。因此,不需要为它们执行任何操作,但系统管理员应调查 I/O 请求耗时很长的原因以及耗时是否合理。

长时 I/O 请求的原因

长时 I/O 消息可能指示 I/O 永久阻塞并且永远无法完成(称为“I/O 丢失”),或者只是它尚未完成。虽然 I/O 丢失往往会导致闩锁超时,但无法根据消息确定是哪种情况。

长时 I/O 往往指示磁盘子系统的 SQL Server 工作负荷过于密集。以下情况可能会指示磁盘子系统不足:

  • SQL Server 工作负荷很大时,错误日志中出现多个长时 I/O 消息。

  • Perfmon 计数器显示磁盘长时间滞后、磁盘队列长或无磁盘空闲时间。

长时 I/O 还可能因以下原因所致:I/O 路径中的某个组件(如驱动程序、控制器或固件)不断延迟为早期 I/O 请求提供服务,而为距离当前磁头位置较近的新请求提供服务。这种对距离读/写磁头当前位置最近的请求进行优先处理的常见技术称为“电梯式查找”。它可能很难与 Windows 系统监视器 (PERFMON.EXE) 工具配合使用,因为多数 I/O 是立即获得服务的。执行大量连续 I/O 的工作负荷可能会使长时 I/O 请求情况更严重,如备份和还原、表扫描、排序、创建索引、大容量加载以及清零文件。

单独出现的长时 I/O 如果与上述情况无关,则可能是由硬件或驱动程序问题所致。系统事件日志可能会包含有助于进行问题诊断的相关事件。

错误检测

数据库页可使用下面两种可选机制之一来保证页在从写入磁盘到再次读取期间的完整性:残缺页保护和校验和保护。这两种机制允许采用独立方法验证数据存储以及诸如控制器、驱动程序、电缆等硬件组件甚至操作系统的正确性。在即将把页写入磁盘之前将向页添加保护,并在从磁盘读取页后对它进行验证。

残缺页保护

SQL Server 2000 中引入的“残缺页保护”其实是一种对电源故障导致的页损坏进行检测的方法。例如,意外电源故障可能导致只有部分页写入磁盘。使用残缺页保护时,页的每个 512 字节扇区末尾会放置一个 2 位签名(在将原来的 2 位复制到页头之后)。每次进行写操作时,这个签名在二进制数 01 和 10 之间交替,这样始终可以确定是否只有部分扇区写到磁盘:如果稍后读取页时发现某个位的状态不正确,则说明该页没有被正确写入并会因此检测到残缺页。残缺页检测使用的资源最少,但是它无法检测到磁盘硬件故障导致的所有错误。

校验和保护

SQL Server 2005 中引入的“校验和保护”提供了更强大的数据完整性检查。此方法将对写入每一页中的数据进行校验和计算并将其值存储在页头中。每次从磁盘读取存储了校验和的页时,数据库引擎将重新计算页中数据的校验和。如果新的校验和不同于已存储的校验和,则引发错误 824。校验和保护比残缺页保护能捕获到更多的错误,因为它受到页中每个字节的影响,但它对资源的消耗较多。启用校验和后,当缓冲区管理器从磁盘读取页时均可以检测到因电源故障以及硬件或固件故障导致的错误。

页保护类型是包含此页的数据库的属性之一。校验和保护是在 SQL Server 2005 和更高版本中创建的数据库的默认保护。页保护机制是在创建数据库时指定的,并且可以使用 ALTER DATABASE 进行更改。可通过查询 sys.databases 目录视图中的 page_verify_option 列或 DATABASEPROPERTYEX 函数的 IsTornPageDetectionEnabled 属性来确定当前的页保护设置。如果页保护设置发生变化,新设置不会立即影响到整个数据库。相反,每当下一次写入时,这些页才会采用数据库的当前保护级别。这意味着数据库可能包含带有不同保护的页。