SQL SERVER 日志写入原理浅析
昨天看到网上有一个关于SQL SERVER 课件,便随手下载了下来看看主要讲了些什么内容,于是看到了下面两个PPT页面
![]()
![]()
由于第一张PPT上的内容不太准确(日志文件中没有“日志页”的概念,只有VLF的概念,可能是我们对“数据页”的概念太深刻了,因此弄了以“日志页”的概念出来,而PPT中说先更新高速缓冲区中的数据页,然后将事务日志写入到“日志页”,很容易让人理解成先更改高速缓冲区,然后将日志写入到磁盘上的“日志页”),再加上我看PPT时比较"囫囵"(只看到前一张PPT,没有往后翻两下看后面一张PPT).因此我觉得PPT的作者在日志的写入顺序上有问题.索性查了一下资料,然后比较深入的思考了日志的写入顺序问题,同时也纠正了一些自己以往的不正确理解.
该文主要包含以下内容:
     1.SQL SERRVER 日志管理器的大致工作内容与原理.
     2.实例探究SQL SERVER 事务日志的产生与写入磁盘磁盘. 
     3.一些其它的相关思考.
第一部分:SQL SERVER 日志管理器的大致工作原理.
日志管理器承担着事务日志的编排与写入工作。它维护着一个或多个被称之为“日志缓存”的连续的专用内存区域。由于SQL SERVER 事务日志必须按照一定的格式写入到日志文件中,因此日志缓存中的功能之一就是用来编排日志的格式。而当一个日志缓存区域被占满的时候,还有一个或多个日志缓存区域可以被用来保存新产生的日志记录。 
    其次,日志管理器维护着两个日志缓存队列,一个flushQueue,另一个是freeQueue。其中flushQueue包含的是等待被刷新到日志文件(物理磁盘)的日志缓存;freeQueue包含的是已经被刷新并且可以被再次使用的日志缓存。 
    而日志的刷新工作主要一个被称之为“日志编写器”的线程来负责,它将依次遍历 flushQueue,一次仅将一个当前的日志缓存中的内容写入到磁盘上。 
    而日志编写器的刷新工作由什么来触发呢?当一个事务被提交时或者日志缓存被占满时,当前的日志缓存就被放入flushQueue,日志编写器就必须开始工作。日志编写器的工作完成后, 日志管理器将会收到一个写入成功的信号,进而激活所有正在等待日志缓存刷新的所有进程,以继续完成工作。
第二部分:实例探究SQL SERVER 事务日志的产生与写入磁盘。
    当一个更新语句被发出并获得相关锁以后,SQL SERVER 将先更改高速缓冲区中的相关数据页,在更改高速缓冲区中的页时,将会产生一条日志记录并放到日志缓存中,当这个更新语句被提交(COMMIT)时,这条存在于当前日志缓存中的日志记录将首先被成功刷新到磁盘上的日志文件中以后,再返回“更新成功”的确认信息到客户端。以上是事务比较“小”的时候日志写入的相关情况。而当事务比较“大”时,尽管事务没有被COMMIT,而日志也会被写入到磁盘上。 
   下面我将以实例来证明以下几种情况: 
    A. 当事务比较“小”时,只有事务被COMMIT时,日志才会被写入到磁盘上的日志文件中。 
    B. 当事务比较“大”时,尽管事务没有被COMMIT,日志也会被写入磁盘上的日志文件中。
实例一:要证明情况A比较麻烦,因为需要在事务被开始但没有被COMMIT时,查看磁盘上的日志文件中是否有相关的日志记录。而SQL SERVER 虽然提供了一个未公开的查看日志记录的命令DBCC LOG(数据库名),但是这个命令却会将存在于日志缓冲区内没有实际写入磁盘的日志记录一并列出来。因此我不得不借助一个大家熟知的第三方工具Log Explorer。
试验步骤: 
    1.建立一个测试数据库northwind,恢复模式为完整。并且对其进行一次完整备份(这样SQL SERVER 才能将日志保存,否则将会被定期截断),运行CHECKPOINT命令,然后再进行一次事务日志备份以截断所有不活动的日志。运行一下命令DBCC LOG(northwind)看看情况。  
        
 
   在上图的结果中,你将只能看到Operation分别为LOP_BEGIN_CKPT和LOP_END_CKPT的两条日志。这两条日志是刚刚进行“事务日志备份”而产生的两条日志,而其它的日志已经被截断。
2.测试数据库中建立一个表TEST(ORDER_ID INT,ZDESC VARCHAR(100) ),然后插入一条测试数据。
CREATE TABLE TEST
(
ORDER_ID INT,
ZDESC VARCHAR(100)
) GO INSERT INTO TEST(ORDER_ID,ZDESC)
VALUES( 1,’a’)
GO
成功执行后,我们再运行DBCC LOG(northwind)看看日志的情况: 
    ![]()
3.然后我们运行以下命令:
BEGIN TRAN
UPDATE TEST SET ZDESC=’B’
WHERE ORDER_ID=1
该命令开始了一个事务,将ZDESC列的值更改为‘B’,但是该事务没有被COMMIT.  
      运行DBCC LOG(northwind)查看日志的情况。 
   
 
   大家注意看第54条日志,从第54条日志开始,就是我们运行上面的UPDATE事务所产生的所有日志,由于该事务并没有被COMMIT,我们必须想办法查看自54号日志开始的所有日志是否已经保存到了磁盘的日志文件中。这时,我们先将SQL SERVER服务改为手动启动,然后强行重新启动电脑,启动电脑后,在SQL SERVER未启动以前,拷贝northwind的日志文件到其它目录(虽然我们可以在电脑启动后,SQL SERVER 服务启动以后再次运行DBCC LOG(northwind)来查看日志的情况,但是我担心SQLSERRVER在启动的时候会进行恢复工作而对没有提交的日志进行什么处理),我们还是利用Log Explorer来查看拷贝出来的日志文件中的日志记录。 
   我们还是先DBCC LOG(northwind)看看情况: 
   
 
  大家可以看到,先前的序号64,65号日志已经看不到了,而这两条日志,就是UPDATE语句产生的真正的日志,而54-63是进行修改工作系统内部的一些事务。然后我们再用Log Explorer来看看之前拷贝出来的日志文件中的日志。 ![]()
上图是Log Explorer显示的备份出来northwind的日志文件的详细情况,我们可以在上面的表格栏选中某一条日志,然后注意红色框框出来的LSN.LSN:36:87:1这条日志即是我们用DBCC LOG(northiwind)命令所显示的排序为64的即CurrentLSN为:00000036:00000087:0001这条日志,很明显,Log Explorer显示的这条日志和先前DBCC LOG(northiwind)显示出的日志并不相同,因此我们可以断定,一个“小”的事务在未被COMMIT以前,日志已经产生,并且存储在日志缓冲区,但没有写入到磁盘的日志文件中。而一旦该事物被COMMIT,日志将一定会被写入磁盘,这种情况各位园友可以自己去实际验证。
实例二:证明情况B比较简单,我们只需要让SQL SERVER运行一个较“大”的事务,然后观察磁盘上日志文件有没有被自动增长,如果增长了,那么日志肯定被写入到磁盘上了。
实验步骤: 
1.观察northiwind当前日志文件的大小。因为我的northwind是刚刚新建的数据库,日志文件的物理大小为1M. 
2.运行以下脚本,然后在观察日志文件的物理大小。
BEGIN TRAN
DECLARE @I INT
SET @I=1
WHILE(@I<99999)
BEGIN
UPDATE TEST SET ZDESC=LEFT(NEWID(),10)
SET @I=@I+1
END
该脚本被封装成一个事务,并且没有被提交(COMMIT),运行完成后,我观察到的日志文件的物理大小为38.3M,如下图: 
 
很明显,尽管该事务没有被提交(COMMIT),但是,只要日志缓冲区被填满,日志缓存中的日志就会被写入到物理磁盘上。及时我们回滚了该事务,我们依然可以用DBCC LOG(northwind)看到这些被回滚的日志。
第三部分:其它一些相关问题的思考 
    1.当SQL SERVER修改高速缓冲区中的数据页时,日志便会产生,并放入到日志缓存。那么日志究竟是由缓冲区管理器产生后交给日志管理器,还是由日志管理器探测到缓冲区的修改,然后自己产生日志。 
    2.日志缓冲中的日志,究竟要“编排”成什么格式?是否就是我们通过DBCC LOG(northwind)所看到的格式。 
    3.日志编写器在讲日志写入磁盘时,如何知道该写到日志文件的哪一个VLF,也就是说它是如何知晓某个VLF是逻辑上的最后一个VLF。
后文
关于Virtual Log Files(虚拟日志文件)参考这里
关于Write-Ahead Logging (预写日志)参考这里
转自:https://www.cnblogs.com/zhouqiang52154/archive/2009/06/20/1507488.html
SQL SERVER 日志写入原理浅析的更多相关文章
- 清理SQL Server日志释放文件空间的终极方法
		
清理SQL Server日志释放文件空间的终极方法 转自:http://www.cnblogs.com/dudu/archive/2013/04/10/3011416.html [问题场景]有一个数 ...
 - 收缩SQL Server日志不是那么简单
		
收缩SQL Server日志不是那么简单的(翻译) 原文地址:http://rusanu.com/2012/07/27/how-to-shrink-the-sql-server-log/ 说明:本 ...
 - sql server 日志文件结构及误操作数据找回
		
一. 概述 在sql server 里有数据文件.mdf和日志文件.ldf,日志文件是sqlserver数据库的另一个重要组成部分,日志文件记录了所有事务以及每个事务对数据库所做的修改.为了提高数据库 ...
 - SQL Server on Linux 理由浅析
		
SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...
 - SQL Server日志文件庞大收缩方法(实测好用)
		
原文:SQL Server日志文件庞大收缩方法(实测好用) 这两个命令连续执行,间隔时间越少越明显(可多次运行),直到达到效果 --截断 BACKUP LOG CloudMonitor TO DISK ...
 - SQL Server 日志和代理的错误日志
		
本文介绍的日志不是事务日志,而是SQL Server 日志和代理的错误日志,按照主体把错误日志分为SQL Server.SQL Server Agent.Database Mail,以及 Window ...
 - SQL Server日志文件过大 大日志文件清理方法 不分离数据库
		
SQL Server日志文件过大 大日志文件清理方法 ,网上提供了很多分离数据库——〉删除日志文件-〉附加数据库 的方法,此方法风险太大,过程也比较久,有时候也会出现分离不成功的现象.下面的方式 ...
 - 解决Sql Server 日志满了,设置收缩
		
解决Sql Server 日志满了,设置收缩: --查看文件占用空间 . '文件大小(MB)',* from sysfiles; ALTER DATABASE SpyData SET RECOVERY ...
 - 误删SQL Server日志文件后怎样附加数据库
		
SQL Server日志文件因为误操作被删除,当附加数据库的时候提示:附加数据库失败. 解决办法如下: 1.新建一个同名数据库. 2.停止数据库服务,覆盖新建的数据库主文件(小技巧:最好放在同一个磁盘 ...
 
随机推荐
- 一种动态的样式语言--Less 之 命名空间
			
LESS 命名空间 如果想更好的组织CSS或者单纯是为了更好的封闭,将一些变量或者混合模块打包起来,你像下面这样在#bundle中定义一些属性集之后可以重复使用: #bundle{ .button() ...
 - selenium 2 设置浏览器安装路径
			
selenium 2由于调用的是真实的浏览器,所以当你的浏览器不是安装在默认路径下,你就需要设定浏览器启动路径:若是默认路径,则程序中不需设定浏览器启动路径. 比如说用firefox进行测试 1. f ...
 - Numpy | 11 迭代数组
			
NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式. 迭代器最基本的任务的可以完成对数组元素的访问. 实例1:使用 arange() 函数创建一个 2x3 ...
 - 服务器使用ssh秘钥登录并禁止密码登录
			
问题: 最近在登录服务器的时候,每次都会有提示999+ falied login等字眼,意思就是自己的服务器密码正在被人暴力破解.想象以下,别人有了你的服务器的root登录密码,那么就可以对你的服务器 ...
 - plsql tables 表存在,但是看不到所有的表信息
			
1.情景展示 tables目录存在,但是看不到该数据库下的表信息. 2.解决方案 对比同事的发现,原来是选错用户了. 将用户切换为当前用户就行了,不知道什么时候搞成所有用户了. 写在最后 哪位大佬 ...
 - Json文件的BOM
			
1.什么是BOM BOM: Byte Order Mark UTF-8 BOM又叫UTF-8 签名,其实UTF-8 的BOM对UFT-8没有作用,是为了支持UTF-16,UTF-32才加上的BOM,B ...
 - [技术博客]JSCover+selenium获得js代码覆盖率
			
本文档讲解了我们是如何使用JSCover来获得Selenium的测试样例的js代码文件的执行覆盖率的. 事实上网上有挺多博客讲这玩意儿了,不过完全按照网上已有的教程去弄的的话,并无法满足我们的需要. ...
 - 自顶向下深入分析Netty(七)--ChannelPipeline和ChannelHandler总述
			
自顶向下深入分析Netty(七)--ChannelPipeline和ChannelHandler总述 自顶向下深入分析Netty(七)--ChannelPipeline源码实现 自顶向下深入分析Net ...
 - 福昕PDF高级企业版编辑器9.5 Foxit PhantomPDF Business安装破解教程
			
title: "福昕PDF高级企业版编辑器9.5 Foxit PhantomPDF Business安装破解教程" categories: soft tags: soft auth ...
 - Vue 项目中断点没有跳转到指定源码的问题
			
将配置中 devtool 改为以下即可. devtool: 'source-map' 如果是在 vue-cli 2.x ,那么就在 webpack.dev.config.js 中 如果是 vue-cl ...