0.参考文献

Microsoft SQL Server企业级平台管理实践 第11章

Buffer Latch Timeout的解析

什么是PAGELATCH和PAGEIOLATCH

1.PAGELATCH_x和PAGEIOLATCH_x介绍

在分析SQL server 性能的时候你可能经常看到 PAGELATCH和PAGEIOLATCH。比方说执行如下TSQL语句

Select * from sys.dm_os_wait_stats

它输出结果里面就有Latch的有关信息,如下图所示:

1.1什么是LATCH呢?

Latch是SQL server内部用来同步资源访问的一个数据结构,和操作系统的critical section 或 ReaderWriterLock类似。Latch保护了那些想保护的资源,使得访问同步有序。比方说,当某个线程获得某个资源的latch的独占使用权的时候,别的线程如果也需要访问这个latch则它必须等待。那么又有新的疑问,latch和lock有什么区别呢?主要是使用的地方和目的不一样。Latch用来保护SQL server内部的一些资源(如page)的物理访问,可以认为是一个同步对象。而lock则强调逻辑访问。比如一个table,就是个逻辑上的概念,物理上一个表是有很多页组成的。访问一个表的记录的时候,首先可能需要获得表的共享锁,然后获得某个页的latch,然后就可以读取该页的记录。Lock是全局性的,由统一的lock manager管理。而latch没有统一的manager管理的。

1.2什么是PAGELATCH呢?

PAGELATCH_x类型的latch是SQL Server在缓冲池里的数据页面上经常加的一类latch。它用来同步访问buff pool中的数据页。SQL server中的Buff pool里每个page都有一个对应的LATCH。 要访问某个PAGE必须首先获得这个PAGE的LATCH。PAGELATCH有很多种,如共享的PAGELATCH_SH,独占的PAGELATCH_EX等。独占的意思是排他性访问,只有一个线程可以访问,一般用户update,insert和delete操作。共享的意思是可以有多个线程同时获得这个latch。下面以在同一个data page中插入输入数据来说明pagelatch。可以参考博客:Buffer Latch Timeout的解析

每个SQL Server的数据页面大致分成3个部分:页头、页尾偏移量和数据存储部分。假设现在有一个表格的结构是:

CREATE TABLE test (
a int,
b int
)

它在1:100这个页面上存储数据。那么这个页面结构大致如下图所示:

在页头部分,会记录页面属性,包括页面编号等,还会记录当前页面空闲部分的起始位置在哪里(m_freedata)。这样SQL Server在要插入新数据的时候,就能够很快地找到开始插入的位置。而页尾部的偏移记录了每一条数据行的起始位置。这样SQL Server在找每一条记录的时候,就能很快找到,不会把前一条记录和后一条搞混。在上图中page:100里现在有两条记录,(1,100)和(2,200)。第一条记录的开始位置是96,第二条的开始位置是111。从126开始,是空闲的空间。这页表明一列的长度是15。当页面里的数据行发生变化的时候,SQL Server不但要去修改数据本身,还要修改这些偏移量的值,以保证SQL Server能够继续准确地管理数据页面里的每一行。

现在假设有两个用户同时要向这张表里插入数据,一个人插入(3,300),另一个插入(4,400)。那么这两个用户会读取相同的(m_freedata=126)
假如没有latch,这两条插入语句可以同时运行。在事务逻辑上,这两条语句插入的是两条不相干的记录,所以不应该相互阻塞,这样处理是正确的。某进程在页面100上,插入如下数据:INSERT VALUES(3, 300),其结果如下:

这时,另外一个进程要在页面100上,插入如下数据: INSERT VALUES(4, 400), 因为没有Latch锁,所以会覆盖之前的数据。导致数据插入出问题。如下图所示:

在逻辑层面上,插入两条数据是互不干扰的,但是在物理存储层面上,就出现了问题。要插入的两条数据读取的空闲空间位置m_freedata=126,都要往这个位置上面插入,那么总有一条数据会被另外一条数据所覆盖,从而导致插入错误。要想办法解决这个冲突,一定要定义出一个先后顺序。SQL Server为了解决这类问题,引入了另一类页面上的latch:PAGELATCH。当一个任务要修改页面时,它必须先申请一个EX的latch。只有得到这个latch,才能修改页面里的内容。所以这里的两个插入任务,不仅申请了页面上的锁,还要申请页面上的排他latch。假设(3,300)这个插入任务先申请到了,那(4,400)这个任务就会被阻塞住。所以,(3,300)这条记录能够被先插入,如下图所示。

当(3,300)插入完成后,它申请的latch被释放,m_freedata的数据被更新。此时(4,400)就能得到latch资源,这是才读取m_freedata,然后往m_freedata位置插入数据。(4,400)被插在了(3,300)的后面。这样,两个插入都正确地完成了,如下图所示。

由于数据页的修改都是在内存中完成的,所以每次修改的时间都应该非常短,几乎可以忽略不计。而PAGELATCH只是在修改的过程中才会出现,所以PAGELATCH的生存周期应该也非常短。如果这个资源成为了SQL Server经常等待的资源,可说明以下问题。

  1. SQL Server没有明显的内存和磁盘瓶颈(恭喜你!)。
  2. 应用程序发来大量的并发语句在修改同一张表格里的记录,而表格架构设计以及用户业务逻辑使得这些修改都集中在同一个页面,或者数量不多的几个页面上。这些页面有的时候也被称为Hot Page。这样的瓶颈通常只会发生在并发用户比较多的、典型的OLTP系统上。
  3. 这种瓶颈是无法通过提高硬件配置解决的,只有通过修改表格设计或者业务逻辑,让修改分散到尽可能多的页面上,才能提高并发性能。
  4. 要在修改表格的设计,从而引入了partition的概念,要解决上述问题,可以通过分区的方式分担hot page上面的压力。具体解决方法参考另外一篇博客:sql server中filegroup与partition解析 。

1.3什么是PAGEIOLATCH呢?

当缓存在内存缓冲池区域里的数据页面,和磁盘上数据文件里的数据页面进行交互时(就是data page不在内存中),为了保证不会有多个用户同时读取/修改内存里的数据页面,SQL Server会像对待表格里的数据一样,对内存中的页面实行加锁的机制,以同步多用户并发处理。不同的是,在这里,SQL Server加的是latch(轻量级的锁),而不是lock。

例如,当SQL Server将数据页面从数据文件里读入内存时,为了防止其他用户对内存里的同一个数据页面进行访问,SQL Server会在内存的数据页面上加一个排他的latch。而当有任务要读缓存在内存里的页面时,会申请一个共享的latch。像lock一样,latch也会出现阻塞的现象。根据不同的等待资源,在SQL Server里等待的状态会是:

PAGEIOLATCH_DT : Destroy buffer page I/O latch
PAGEIOLATCH_EX : Exclusive buffer page I/O latch
PAGEIOLATCH_KP : Keep buffer page I/O latch
PAGEIOLATCH_NL : Null buffer page I/O latch
PAGEIOLATCH_SH : Shared buffer page I/O latch
PAGEIOLATCH_UP : Update buffer page I/O latch

这里来举一个最容易发生的等待“PAGEIOLATCH_SH”,以它做例子,看看这种等待是怎么发生的。如下图所示:

过程解析

  1. 有一个用户请求,须读取整张X表,由Worker X执行。
  2. Worker X在执行表扫描的过程中发现它要读取数据页面1:100。一张表的数据量可能比一个page大,也可能比一个page小。如果进行table scan的话,那么就需要读取所有包含该表数据的page。
  3. SQL Server发现页面1:100并不在内存中的数据缓存里。
  4. SQL Server在缓冲池里找到一个页面的空间,在上面申请一个EX的latch,防止数据从磁盘里读出来之前,有别人也来读取或修改这个页面。对长个page加锁相当于是在内存中预定了一片空间用于存放需要从磁盘中physical read来的page。
  5. Worker X发起一个异步(Asynchronous)I/O请求,要求从数据文件(database file)里读出页面1:100。
  6. 由于是个异步I/O,Worker X可以接着做它下面要做的事情。而下面要做的,就是要读出内存中的页面1:100。读取的动作需要申请一个SH的latch。
  7. 由于Worker X之前已经对这个page1:100申请了一个EX latch还没释放,所以这个SH latch将被阻塞住。Worker X被自己阻塞住了,等待的资源就是PAGEIOLATCH_SH。
  8. 当异步I/O结束后,系统会通知Worker X,你要的数据已经写入内存了,如下图所示:
  9. 这时候EX latch就被释放。接着Worker X得到了它申请的SH latch。
  10. 数据页1:100终于被Worker X读到,读取工作结束,Worker X可以继续下面的操作。

由此可以看到,在发生PAGEIOLATCH类型的等待时,SQL Server一定是在等待某个I/O动作的完成。所以如果一个SQL Server经常出现这一类的等待,说明磁盘的速度不能满足SQL Server的需要,它已经成为了SQL Server的一个瓶颈。

要强调的是,PAGEIOLATCH_x类型等待最常见的是两大类,PAGEIOLATCH_SH和PAGEIOLATCH_EX。PAGEIOLATCH_SH经常发生在用户正想要去访问一个数据页面,而同时SQL Server却要把这个页面从磁盘读往内存。如果这个页面是用户经常有可能访问到的,那么说到底,问题是因为内存不够大,没能够将数据页面始终缓存在内存里。所以,往往是先有内存压力,触发SQL Server做了很多读取页面的工作,才引发了磁盘读的瓶颈。这里的磁盘瓶颈常常是内存瓶颈的副产品。

而PAGEIOLATCH_EX常常是发生在用户对数据页面做了修改,SQL Server要向磁盘回写的时候,基本意味着磁盘的写入速度明显跟不上。这里和内存瓶颈没有直接的联系。

和磁盘有关的另一个等待状态是WRITELOG,说明任务当前正在等待将日志记录写入日志文件。出现这个等待状态,也意味着磁盘的写入速度明显跟不上。

1.4pagelatch和pageiolatch对比

  1. pagelatch是为了保护在buff pool中page的正确读写,比如说有两个线程想同时往一个page中插入数据,如果没有latch控制的话,插入位置存在冲突。所以引入了pagelatch_ex,一次只有一个线程能够得到pagelatch_ex,只有得到pagelatch_ex的线程才能够修改page。
  2. 而pageiolatch是为了数据的异步访问。比如说我们想读取一个page,但是它不内存中,那么sql server会首先在内存中为这个page空出一块空间,并且加上ex_latch,然后在这个page真正从disk读取到内存当中之前,其他线程不能对这片内存进行操作。因为异步操作,所以这个线程会去访问这个page,此时申请sh_latch,但是与之前的ex_latch,最终导致自己被自己阻塞了。这就是pageiolatch_sh
 
关于想要如何减少PAGELATCH_EX等待,请参阅 如何识别和解决SQL Server中的热闩锁

SQL Server 中PAGELATCH_x和PAGEIOLATCH_x解析的更多相关文章

  1. sql server中replace()函数用法解析

    知识点一:replace()的语法 REPLACE ( string_replace1 , string_replace2 , string_replace3 ) 参数解析: string_repla ...

  2. Microsoft SQL Server中的事务与并发详解

    本篇索引: 1.事务 2.锁定和阻塞 3.隔离级别 4.死锁 一.事务 1.1 事务的概念 事务是作为单个工作单元而执行的一系列操作,比如查询和修改数据等. 事务是数据库并发控制的基本单位,一条或者一 ...

  3. sql server中对xml进行操作

    一.前言 SQL Server 2005 引入了一种称为 XML 的本机数据类型.用户可以创建这样的表,它在关系列之外还有一个或多个 XML 类型的列:此外,还允许带有变量和参数.为了更好地支持 XM ...

  4. 谈一谈SQL Server中的执行计划缓存(上)

    简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询 ...

  5. SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题

    用户定义函数(UDF)分类  SQL SERVER中的用户定义函数(User Defined Functions 简称UDF)分为标量函数(Scalar-Valued Function)和表值函数(T ...

  6. 如果正确读取SQL Server中的扩展事件?

        SQL Server中使用扩展事件捕捉所需的信息后,可以选择存放的位置.比如说内存或文件中,但无论存在哪里,其本质都是一个大XML.因此在SQL Server中读取该XML就是解析扩展事件结果 ...

  7. 关于SQL Server中分区表的文件与文件组的删除(转)

    在SQL Server中对表进行分区管理时,必定涉及到文件与文件组,关于文件与文件组如何创建在网上资料很多,我博客里也有两篇相关转载文件,可以看看,我这就不再细述,这里主要讲几个一般网上很少讲到的东西 ...

  8. 浅析SQL Server中的执行计划缓存(上)

    简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询 ...

  9. SQL Server中的执行引擎入门

      简介 当查询优化器(Query Optimizer)将T-SQL语句解析后并从执行计划中选择最低消耗的执行计划后,具体的执行就会交由执行引擎(Execution Engine)来进行执行.本文旨在 ...

随机推荐

  1. Opencv颜色识别与追踪

    这是基于颜色识别的物体追踪 不废话 直接看代码 这是Opencv3的代码 //---------------------------------[头文件.命名空间包含部分]-------------- ...

  2. 不会前后端,用vps搭建个人博客(二)

    <接上一篇>   四.添加网页内容 1.下载安装WordPress 输入以下命令: wget https://wordpress.org/latest.tar.gz 当然你也可以用浏览器进 ...

  3. Mac Mini(late 2014) 添加NVMe固态组Fusion Drive

    我买的是Mac Mini(late 2014)中配,内置5400转1T机械硬盘,该配置即使到了2019年安装macOS Mojave系统依旧是够用的,但硬盘严重拖累了运行的速度.之前考虑到更换内置sa ...

  4. Golang转义字符

    Golang常见的转义字符(escape char) \t    一个制表位,实现对齐的功能 \n   换行符 \\    一个\ \"    一个" \r    一个回车  fm ...

  5. nginx+lua+storm的热点缓存的流量分发策略自动降级

    1.在storm中,实时的计算出瞬间出现的热点. 某个storm task,上面算出了1万个商品的访问次数,LRUMap 频率高一些,每隔5秒,去遍历一次LRUMap,将其中的访问次数进行排序,统计出 ...

  6. Python基础知识(四)

    Python基础知识(四) 一丶列表 定义格式: 是一个容器,由 [ ]表示,元素与元素之间用逗号隔开. 如:name=["张三","李四"] 作用: 存储任意 ...

  7. Weak Session IDs

    工具的使用 首先github上下载火狐插件(正版收费),按F12调用 服务器生成sessionID通过response返回给浏览器,sessionID存放在浏览器cookie中,然后再通过cookie ...

  8. js节流与防抖函数封装

    js节流与防抖函数封装 常见应用场景: window的 resize 和 scroll 事件: 文字输入时的 keyup 事件: 元素拖拽.移动时的 mousemove 事件: 防抖 定义:多次触发事 ...

  9. Node中require第三方模块的规则

    Node.js中使用CommonJs模块化机制,通过npm下载的第三方包,我们在项目中引入第三方包都是:let xx = require('第三方包名'),究竟require方法加载第三方包的原理机制 ...

  10. oracle中start with和connect by的用法理解

    转自:https://blog.csdn.net/qq_29274091/article/details/72627350 Oracle中start with和connect by 用法理解转自:ht ...