昨天看到网上有一个关于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 日志写入原理浅析的更多相关文章

  1. 清理SQL Server日志释放文件空间的终极方法

    清理SQL Server日志释放文件空间的终极方法  转自:http://www.cnblogs.com/dudu/archive/2013/04/10/3011416.html [问题场景]有一个数 ...

  2. 收缩SQL Server日志不是那么简单

    收缩SQL Server日志不是那么简单的(翻译)   原文地址:http://rusanu.com/2012/07/27/how-to-shrink-the-sql-server-log/ 说明:本 ...

  3. sql server 日志文件结构及误操作数据找回

    一. 概述 在sql server 里有数据文件.mdf和日志文件.ldf,日志文件是sqlserver数据库的另一个重要组成部分,日志文件记录了所有事务以及每个事务对数据库所做的修改.为了提高数据库 ...

  4. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  5. SQL Server日志文件庞大收缩方法(实测好用)

    原文:SQL Server日志文件庞大收缩方法(实测好用) 这两个命令连续执行,间隔时间越少越明显(可多次运行),直到达到效果 --截断 BACKUP LOG CloudMonitor TO DISK ...

  6. SQL Server 日志和代理的错误日志

    本文介绍的日志不是事务日志,而是SQL Server 日志和代理的错误日志,按照主体把错误日志分为SQL Server.SQL Server Agent.Database Mail,以及 Window ...

  7. SQL Server日志文件过大 大日志文件清理方法 不分离数据库

    SQL Server日志文件过大    大日志文件清理方法 ,网上提供了很多分离数据库——〉删除日志文件-〉附加数据库 的方法,此方法风险太大,过程也比较久,有时候也会出现分离不成功的现象.下面的方式 ...

  8. 解决Sql Server 日志满了,设置收缩

    解决Sql Server 日志满了,设置收缩: --查看文件占用空间 . '文件大小(MB)',* from sysfiles; ALTER DATABASE SpyData SET RECOVERY ...

  9. 误删SQL Server日志文件后怎样附加数据库

    SQL Server日志文件因为误操作被删除,当附加数据库的时候提示:附加数据库失败. 解决办法如下: 1.新建一个同名数据库. 2.停止数据库服务,覆盖新建的数据库主文件(小技巧:最好放在同一个磁盘 ...

随机推荐

  1. 使用Google学术简单方法汇总

    1 Google学术打不开,简单方法汇总. 2   谷歌学术镜像 http://dir.scmor.com/google/ 3,https://xs.glgoo.net/ 4, https://sch ...

  2. SDOI2019快速查询

    链接 vijos 思路 虽然询问1e7,但他询问很有意思,所以最多修改1e5个. 先把他们修改的点缩小到1e5之内并没有什么影响. 然后维护mul和add.不修改很好弄,修改的点可以弄点式子加加减减弄 ...

  3. 数列的通项公式$a_n$的求法

    前言 求数列的通项公式,其本质是求函数的解析式.重点理解内涵. 求解必备 你见到这样的式子\(a_{n+1}-a_n = m\) (\(m\)常数)你一定会反应出是等差数列,那么见到 \(S_{n+1 ...

  4. 超级经典的HTTP协议讲解

    - HTTP 协议 HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展. HTTP 协议的主 ...

  5. linux 如何改变文件属性与权限1

    我们知道档案权限对于一个系统的安全重要性,也知道档案的权限对于使用者与群组的相关性, 那如何修改一个档案的属性与权限呢? 我们这里介绍几个常用于群组.拥有者.各种身份的权限的指令.如下所示: chgr ...

  6. 数据接口-免费版(股票数据API)

    获取股票数据的源头主要有:数据超市.雅虎.新浪.Google.和讯.搜狐.ChinaStockWebService.东方财富客户端.证券之星.网易财经. 数据超市 2016年5月6日更新.根据最近频繁 ...

  7. leetcode: 最长上升子序列

    题目描述: 给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7,101,18]输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 ...

  8. openssl 自己制作ssl证书:自己签发免费ssl证书,为nginx生成自签名ssl证书

    server { listen 80; listen 443 ssl; server_name ~^((cloud)|(demo-cloud)|(demo2-cloud)|(approval1))(( ...

  9. 《Go语言实战》读书笔记

    <Go语言实战>中文版pdf 百度网盘: https://pan.baidu.com/s/1kr-gMzaPAn8BFZG0P24Oiw 提取码: r6rt 书籍源码:https://gi ...

  10. django文章对本项目有用的收集

    1.在django中使用自定义标签实现分页功能 https://www.cnblogs.com/MnCu8261/p/5943609.html https://www.cnblogs.com/bail ...