SQL Server架构----查询的生命周期(下)

时间:2021-10-27 01:26:56

上一篇介绍了关系引擎和存储引擎、缓冲池和基本的SELECT语句的生命周期。这里将介绍简单的UPDATE查询生命周期及恢复。

 

简单的UPDATE查询

UPDATE的过程在到达访问方法之前,和SELECT完全一样。对于UPDATE,访问方法需要做数据更新,因此,在I/O请求被传递之前,修改的细节需要持久化到磁盘,这就是事务管理器的工作。

 

事务管理器

事务管理器由两个组件,锁管理器和日志管理器。锁管理器负责对数据提供并发性,它通过使用锁来提供隔离的配置级别。访问方法代码请求把它想做的修改记录下来,日志管理器就把修改写入事务日志。这就是所谓的预写日志WAL-write-ahead logging

写入事务日志仅仅是数据修改事务的一部分,数据修改事务总是需要物理写入磁盘,因为倘若SQL Server发生故障,就要依靠它来重读修改。事务日志里存储的是页变更的细节,而页变更是修改声明的结果。SQL Server的这种需要是为了撤消变更,也是你很难读取事务日志的内容的原因所在,除非你能购买第三方工具来读取。

回到UPDATE查询生命周期,更新操作会被写入日志。仅当操作物理写入事务日志被确认后,实际的数据修改才会发生,这就是为何事务日志执行如此关键的原因。一旦访问方法收到确认,它就把修改请求发送到Buffer Manager去完成。

下图显示了事务管理器被访问方法和事务日志呼叫,事务日志是用于记录更新。缓存区管理器此时也会其作用,因为修改请求要准备完成了:

SQL Server架构----查询的生命周期(下)

缓存区管理器

缓存里已经有了需要修改的页,因此,Buffer Manager需要做的,就是根据Access Methods提交的更新请求来修改页。页在缓存里被修改,并且确认会被发回Access Methods,最后到达客户端。

这里的关键点是,UPDATE语句在数据缓存里修改了数据,而不是磁盘上实际的数据库文件。这点是出于性能原因而做出的,页现在就是所谓的脏页,因为它在内存里,不同于在磁盘。这不会影响修改的持久性,因为你可以使用事务日志重新创建修改。

下图显示了UPDATE的完整生命周期。Buffer Manager已经在缓存里完成了页的修改,并传回确认,数据库数据文件在操作期间不可访问,如下面的图:

SQL Server架构----查询的生命周期(下)

 

恢复

修改首先写入事务日志,然后仅在内存实现。这样做是因为性能的原因,它能让你在必要的时候从事务日志里恢复修改。

脏页

从磁盘里读到内存的页被视为干净的页,因为它完全和磁盘上的一样。然而,页一旦在内存里被修改,就被标识为脏页。干净的页可以使用dbcc dropcleanbuffers刷新,但脏页则不可以。

你可以使用如下语句查看各个数据库的脏页大小(size*8\1,024MB)

SELECT db_name(database_id) AS 'Database',count(page_id) AS 'Dirty Pages'
FROM sys.dm_os_buffer_descriptors
WHERE is_modified =1
GROUP BY db_name(database_id)
ORDER BY count(page_id) DESC

每当可用缓存区列表(free buffer list)低或出现检查点时,脏页就会被写回数据库文件。SQL Server始终试图在缓存里保持一些可用的页以便快速分配页,这些可用的页就在可用缓存区列表。当一个工作线程发出一个读请求时,它将获取缓存里的64个页,并检查是否可用缓存区列表低于一定的阈值。如果是,它将会尝试在列表里置换出一些页,这会导致任何脏页写入磁盘。另一个所谓的Lazy writer的线程也会基于低可用缓冲区列表工作。

Lazy Writer

Lazy Writer是一个定期检查free buffer list大小的线程。当它低的时候,它就会扫描整个数据缓存,以老化(age-out)一段时间内未被使用的页。如果发现一段时间内未被使用的脏页,它们就会在内存标记为可用之前,刷新到磁盘。Lazy writer还会监视服务器上可用的物理内存,并在Windows处于低内存时,从可用的缓存区列表中释放出内存给Windows。当SQL Server繁忙时,如果有可用的物理内存并且尚未达到配置的Max Server Memory阈值,它也会增大可用的缓存区列表以满足需求。

检查点进程
检查点时检查点进程创建的一个时间点,在这个点,SQL Server能够确定任何已提交的事务已经把它们所做的修改写入磁盘。这个检查点之后就变成SQL Server恢复的开始点。检查点进程确保与已提交事务关联的任何脏页被刷新到磁盘。它也能把未提交的脏页刷新到磁盘,以便高效写入。不像Lazy Writer,检查点不会从缓存中移除页,它确保脏页写入磁盘,然后在页头把缓存的页标记为干净的。

默认情况下,在繁忙的服务器上,SQL Server大约每分钟发出一个检查点,检查点被标记在事务日志中。如果SQLServer实例或数据库被重启,那么恢复处理读取日志就会知道,无需根据检查点之前的日志记录做任何事情。最后一个检查点之后发生的已提交的事务需要前滚(继续完成),未提交的事务需要回滚(撤消)。SQL Server尝试通过检查点将恢复时间控制在1分钟之内,除非这个期间至少有10MB写入日志,否则不会自动创建检查点。检查点可以通过T-SQL命令CHECKPOINT 手动创建,也可以发生在其他时间发生时,例如,当你发出备份命令时,检查点将首先运行。当检查点启动和停止时,跟踪标记3502会记录在错误日志中。

 

恢复间隔

恢复间隔是一个服务器的配置选项,可以用来影响两个检查点间的时间。默认情况下,恢复时间间隔设置为0,这使SQL Server能够选择一个合适的间隔,这通常等同于自动检查点之间大约一分钟。

恢复模式

有三种恢复模式,完整、大容量日志和简单。

完整:所有的操作完全记录在事务日志中,必须有一个备份策略,包括完整备份和事务日志备份。SQL Server最高恢复级别需要使用完整恢复模式。

大容量日志:倾向用于临时性的特定的bulk操作,最低限度地记录日志以便提升性能,所有其他操作则完全记录日志,如同完整模式。这可以提升性能,因为仅仅记录回滚事务所需要的信息。重做信息不被记录,这意味着你也会失去时间点恢复(point-in-time-recovery)。Bulk操作包括BULK INSERT、bcp、SELECT INTO、CREATE INDEX、ALTER INDEX REBUILD和DROP INDEX。使用大容量日志模式的目的是让你更快地完成大容量日志操作,对于你的事务日志备份而言,它不会减少磁盘空间需求。

简单:每次检查点发生时,所有提交的事务的事务日志被截取。这保证了日志的大小保持最小,事务日志备份不需要。