SQL Server 维护着一个叫做buffer cache的东西, 在buffer cache中SQL Server 读取必须被取回的data pages. 数据在修改时并不是直接写到磁盘上的, 而是写在buffer cache中原本在磁盘上的对应数据页的拷贝中. 修改什么时候落盘呢? 答案是在checkpoint发生的时候, 或者是当修改必须被写回到磁盘上之后buffer cache才可以腾出空间用来放新的页面的时候. 把buffer cache中被修改了的数据写回到盘上的过程叫做flushing the page. 如果一个page在cache中被修改了, 但是还没写到磁盘上, 那么它就叫做dirty page.
任何时候, 只要buffer cache中的page一有修改, 那么一条记录就会被写在log cache中用来记录这次修改. 这条日志记录必须在dirty page被从buffer cache给flush到盘上之前先被写到盘上. 如果dirty page在log record之前被写到了盘上, 那么这个dirty page就在磁盘上创建了一次修改, 该修改在当server挂掉而log record还没落盘的时候是不能回滚的.
SQL Server有阻止dirty page在log record写好之前被flush到磁盘上的逻辑. 当transaction commit了之后, log record才会被写到盘上, 之后dirty page才可以被flush到盘上.
先后顺序如下:
Commit Transaction –> Log record written to disk –> Dirty page flush to disk.
从IO的角度来看, 数据库引擎生成的写IO有两种, 一种叫做logical write另一种叫做physical writes. logical write在buffer cache中的页面有修改的时候发生. physicalwrite在页面从buffer cache中写道盘上的时候发生. 当一个页面在buffer cache中修改了, 它不会马上被写回到磁盘上, 它会被标记为dirty. 这意味着, 一个page可以在physical write发生之前发生多次logical write. 对于每次logical write, 都会有一条transaction log record被添加到log cache中, 用来记录这次修改. 下图说明了写data page的过程:
当buffer manager准备写一个page到盘上的时候, 它会搜索邻近的能够凑成一个集中写操作的dirty page. 邻近的page拥有的是连续的page ID, 并且是来自于相同的file, 这些页面并不需要是在内存中是连续的. 这种搜索是前后两个方向都有的, 会一直持续下去, 直到下面的事件发生:
- 找到了一个clean page
- 找到了32个page
- 找到了一个dirty page, 并且这个dirty page的log sequence number (LSN)还没有被flush到log中去.
- 找到了一个不能被立即latch的page.
通过这种方式, 一个集合的page可以在一个single gather-write operation中写到盘上去.
Dirty page是通过三种方式中的一种写到盘上的:
- Lazy writing - 一个叫做lazy writer的进程会把不常用的page从buffer cache中移除出去, 写到盘上.
- Eager writing – Eager writer进程会将注入bulk insert, select into这样没有log的dirty data page写到盘上.
- Checkpoint - checkpoint进程定期扫描buffer cache, 寻找某个数据库中所有的dirty page, 全部写到盘上.
Lazy writing, eager writing, checkpoint 进程都不会等待IO操作的结束. 他们永远是使用异步IO之后继续他们的工作的, 稍后再检查IO是否成功了. 这能让SQL Server最大化的将CPU和IO资源使用在恰当的任务上.
资料来源
=====================
Write-Ahead Transaction Log
http://technet.microsoft.com/en-us/library/ms186259(v=sql.105).aspx
Writing Pages
http://technet.microsoft.com/en-us/library/aa337560(v=sql.105).aspx