PAGELATCH_x 等待--转载

转自出处: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
时间: 2024-10-25 13:30:47

PAGELATCH_x 等待--转载的相关文章

db file sequential read等待事件 --转载

db file sequential read db file sequential read等待事件有3个参数:file#,first block#,和block数量.在10g中,这等待事件受到用户I/O等待级别的影响.当处理db file sequential read等待事件的时候,牢记以下关键想法. l         Oracle进程需要一个当前不在SGA中的块,等待数据库块从磁盘读入到SGA中 l         要看的两个重要的数字是单独会话的TIME_WAITED和AVERAGE

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. 当一个进程访问需要一个或者多个块时,Oracle会首先检查自己的Cache是否存在该块,如果发现没有,就会先通过global cache赋予这些块共享访问的权限,然后再访问.假如,通过global cache发现这些块已经在另一个实例的Cache里面,那么这些块就会通过Cache Fusion,在节点之间直接传递,

【转载】SQLServer 2012 已成功与服务器建立连接,但是在登录前的握手期间发生错误。 (provider: SSL Provider, error: 0 - 等待的操作过时

楼主用SQL Server 2012 在连接其他电脑的实例时,一直提示“已成功与服务器建立连接,但是在登录前的握手期间发生错误. (provider: SSL Provider, error: 0 - 等待的操作过时.” Google了很多资料,综合自己的问题,并参照官方问题介绍:http://support.microsoft.com/kb/2568167 和另外一位仁兄的博客http://blog.sina.com.cn/s/blog_728bc6a1010182ai.html整理解决方法如

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

最近做一个后来程序,启动了事务后有一段操作业务,当运行一段时间后,出现这个异常 CLR 无法从 COM 上下文 0x1b1c38 转换为 COM 上下文 0x1b1da8,这种状态已持续 60 秒.拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作.这种情况通常会影响到性能,甚至可能导致应用程序不响应或者使用的内存随时间不断累积.要避免此问题,所有单线程单元(STA)线程都应使用泵式等待基元(如 CoWaitForMulti

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

转自:http://blog.csdn.net/barryhappy/article/details/7376231 在应用中经常会用到一些费时的操作,需要用户进行等待,比如加载网页内容…… 这时候就需要一个提示来告诉用户程序正在执行,并没有假死或者真死……囧…… 而ProgressBar.ProgressDialog等就是专门干这个的. 以ProgressDialog为例,一般的使用它步骤为:在执行耗时间的操作之前弹出ProgressDialog提示用户,然后开一个新线程,在新线程里执行耗时的

[转载]HDFS初探之旅

转载自 http://www.cnblogs.com/xia520pi/archive/2012/05/28/2520813.html , 感谢虾皮工作室这一系列精彩的文章. Hadoop集群(第8期)_HDFS初探之旅 1.HDFS简介 HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上.它所具有的高容错.高可靠性.高可扩展性.高

转载:用python爬虫抓站的一些技巧总结

原文链接:http://www.pythonclub.org/python-network-application/observer-spider 原文的名称虽然用了<用python爬虫抓站的一些技巧总结>但是,这些技巧不仅仅只有使用python的开发可以借鉴,我看到这篇文章的时候也在回忆自己做爬虫的过程中也用了这些方法,只是当时没有系统的总结而已,谨以此文为鉴,为以前的爬虫程序做一个总结. 转载原文如下: 学用python也有3个多月了,用得最多的还是各类爬虫脚本:写过抓代理本机验证的脚本,

dubbo连接zookeeper注册中心因为断网导致线程无限等待问题

最近维护的系统切换了网络环境,由联通换成了电信网络,因为某些过滤规则导致系统连不上zookeeper服务器(应用系统机器在深圳,网络为电信线路,zookeeper服务器在北京,网络为联通线路),因为我不是运维人员也不懂运维相关的技术,所以排查了很久也不知道原因,最后无奈之下把深圳这边的网络切回了联通,系统恢复正常. 但是因为本次事故体现了一个很严重的问题,即当zookeeper注册中心连不上时dubbo的线程会无限等待,因为系统有一些定时任务会比较频繁地开启新线程连接dubbo,所以导致的结果是

(转载)Java多线程入门理解

转载出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalangThread类 二实现javalan