转自出处:http://www.cnblogs.com/xwdreamer/archive/2012/08/30/2663232.html

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解析 。

【LATCH申请模式】

Latch在申请的时候有以下几种模式,

  • KP – Keep Latch 保证引用的结构不能被破坏
  • SH – Shared Latch, 读数据页的时候需要
  • UP – Update Latch 更改数据页的时候需要
  • EX – Exclusive Latch 独占模式,主要用于写数据页的时候需要
  • DT – Destroy Latch 在破坏引用的数据结构时所需要

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_x 等待--转载的更多相关文章

  1. SEO优化策略

    原文:http://www.upwqy.com/details/186.html 1 首先了解seo是什么 SEO是英文Search Engine Optimization的缩写,中文译为" ...

  2. java高并发程序设计模式-并发级别:阻塞、无障碍、无锁、无等待【转载】

    一般认为并发可以分为阻塞与非阻塞,对于非阻塞可以进一步细分为无障碍.无锁.无等待,下面就对这几个并发级别,作一些简单的介绍. 1.阻塞 阻塞是指一个线程进入临界区后,其它线程就必须在临界区外等待,待进 ...

  3. (转载)Android自定义ProgressDialog进度等待框

    Android自定义ProgressDialog进度等待框 作者:无缘公子 字体:[增加 减小] 类型:转载 时间:2016-01-11我要评论 这篇文章主要介绍了Android自定义Progress ...

  4. 【转载】一定要会用selenium的等待,三种等待方式必会

    转载地址:http://blog.csdn.net/huilan_same/article/details/52544521,感谢博文,学习了 原文: 发现太多人不会用等待了,博主今天实在是忍不住要给 ...

  5. [转载]sql server 等待类型

    下表列出各任务所遇到的等待类型. 等待类型 说明 ASYNC_DISKPOOL_LOCK 当尝试同步并行的线程(执行创建或初始化文件等任务)时出现. ASYNC_IO_COMPLETION 当某任务正 ...

  6. [转载]Winform等待窗口的实现(附源代码)

    在开发Winform程序的时候,经常会用到等待窗口(如网络通讯.数据库连接等需要一定时间来执行的操作),这样可以给用户提供更好的体验. 等待窗口的主要功能是一边执行需要等待的操作,一边显示一个等待界面 ...

  7. 解决c#所有单线程单元(STA)线程都应使用泵式等待基元(如 CoWaitForMultipleHandles),并在运行时间很长的操作过程中定期发送消息。 转载

    最近做一个后来程序,启动了事务后有一段操作业务,当运行一段时间后,出现这个异常 CLR 无法从 COM 上下文 0x1b1c38 转换为 COM 上下文 0x1b1da8,这种状态已持续 60 秒.拥 ...

  8. 我的Android笔记(十)—— ProgressDialog的简单应用,等待提示 (转载)

    转自:http://blog.csdn.net/barryhappy/article/details/7376231 在应用中经常会用到一些费时的操作,需要用户进行等待,比如加载网页内容…… 这时候就 ...

  9. Oracle RAC 全局等待事件 gc current block busy 和 gc cr multi block request 说明--转载(http://blog.csdn.net/tianlesoftware/article/details/7777511)

    一.RAC 全局等待事件说明 在RAC环境中,和全局调整缓存相关的最常见的等待事件是global cache cr request,global cache busy和equeue. 当一个进程访问需 ...

随机推荐

  1. Python冒号的解释

    1. "没什么首次没有为第二个,跳了三个".它得到的切片序列的每一个第三个项目. 扩展片是你想要的.新在Python 2.3 2. Python的序列切片地址可以写成[开始:结束: ...

  2. 封装及propery的使用

    封装 封装的目的 使类中的属性或者方法只允许在类内部使用,不允许外部对其访问,保证数据的安全性. 封装的方法 使属性或者函数名改写成:"__属性名或者函数名"的格式,即完成了对本类 ...

  3. NGUI_Input

    九.输入框Input 1.凡是用户可以输入文本的地方,几乎都用输入框,有登录账号和密码.输入角色名称.输入聊天内容 2.手动拼接输入框,拖动预制体的就不再说了 (1).创建一个Sprite作为输入框的 ...

  4. APP端的网络优化(DNS优化,HTTP优化)

    一.使用httpDNS优化DNS解析和缓存 一般来说在App内用域名发送请求都要经过DNS解析出ip,然后再根据ip去拿对应的资源,这个过程中,如果LocalDNS中存在这个域名对应的ip,就会直接返 ...

  5. AspNet Core :创建自定义 EF Core 链接数据库

    这两天比较忙,写的会慢一点. 我们以控制台演示 EF Core的链接数据库 首先创建控制台程序 创建数据上下文类 EntityTable /// <summary> /// 继承 DbCo ...

  6. 物联网设备是如何被破解的?分析一种篡改IoT固件内容的攻击方式

    随着智能硬件进入到人们的生活,人们的生活质量开始有逐步的提高,人们与智能硬件之间的联系更加紧密.同时,智能硬件的安全问题也必须引起高度重视,因为其直接影响到人身安全.社会安全和国家安全.   大家是否 ...

  7. 安装cuda8.0中所遇到的问题-解决办法

    正是申请季高峰,但还是被老师抓着干活.之前一直以为cuda已经装好,才知道是骗自己的.我的显卡是640,ubuntu14.4, 比较low. 我是按照这个教程走的,http://m.blog.csdn ...

  8. 如何在BIOS里设置定时关机?

    如何在BIOS里设置定时关机? 通过CMOS设置实现定时开机的设置过程如下: 首先进入"CMOS SETUP"程序(大多数主板是在计算机启动时按DEL键进入): 然后将光条移到&q ...

  9. 【leetcode】123. Best Time to Buy and Sell Stock III

    @requires_authorization @author johnsondu @create_time 2015.7.22 19:04 @url [Best Time to Buy and Se ...

  10. 自学Zabbix3.6.5-触发器item-Unit symbols单位符号

    在zabbix里面,我们不需要使用大数字来,例如我们可以不使用86400来表示一天,这个数字又不容易理解也容易出错.用什么办法来解决大数字问题呢?我们可以使用单位来简化,例如简化zabbix触发器表达 ...