none
关于latch 和 wait stats 的提问 RRS feed

  • 问题

  •  wait_stats 中的等待 和 sys.dm_os_latch_stats有什么区别
    wait_stats 中的 latct_* 和 latch_stats 有又什么联系? 

    latch_stats 中的buffer类型的 和 wait_stats 中的pagelatch 又有什么联系

    2013年4月28日 7:20

答案

全部回复

  • --其他资源等待
    
    --除了上面说的这些最常见的资源等待问题,一个用户任务在某些情况下,还可能
    --等待下面这些资源
    
    --1、LATCH_X
    --在SQL里,除了同步数据页面访问的latch(buffer latch),还有很多其他内部
    --资源要同步。在这些资源上也会出现latch。如果SQL处理得正常,这些latch的申请
    --和释放是非常快的,用户应该不会看到这种等待。但是在一些不正常的情况下,会
    --看到任务在等待某个latch资源。常见的原因有:
    
    --(1)某个先前的任务出现了访问越界(access violation)异常。SQL强行终止了
    --这个任务,但是没能完全将他所申请的所有资源都释放干净,使得某个或者某些latch
    --成为无主孤儿。后面任务要申请同样的latch,都会被阻塞住
    
    --这类问题判断起来比较容易,只要打开SQL日志文件(errorlog),看看出问题之前
    --是否有过access violation问题发生。但是从用户层面上,是没有办法命令SQL申请
    --或释放某个latch资源的。一般只有通过重启SQL服务才能解决问题
    
    
    --(2)SQL同时发生了其他资源瓶颈,例如:内存,线程调度,磁盘等,而latch等待
    --只不过是一个衍生的等待
    
    --(3)当某个数据库文件空间用尽,做自动增长的时候,同一个时间点只能有一个用户
    --任务可以做文件自动增长动作,其他任务必须等待。这时候也会出现latch资源的等待
    
    
    --(4)在一些特殊情况下,有可能是SQL自己没有处理好并发同步,没有使用比较优化
    --的算法,使得用户任务比较容易遇到等待。SQL的一些补丁,就曾经修复过这类问题
    
    
    --所以当看到SQL里的任务出现大量latch等待时,往往是由其他问题衍生而来。
    --首先需要检查SQL是否在健康运行,是否先前已经有过任何异常发生,是否有其他
    --资源瓶颈。只有保证SQL在健康运行,才能谈论这种latch等待。将SQL升级到
    --最新版本,也是一个推荐的做法
    
    
    
    
    --在SQL2000之前,如果出现了跟踪瓶颈,会看到很多latch等待。SQL2005以后,特别加入了
    --以SQLTRACE_X开头的一组等待状态。当看到SQL经常有这样的等待时,除非迫不得已,
    --要立刻停止收集SQL TRACE,尤其是用SQL SERVER PROFILER收集跟踪这样的行为。
    --关于如何收集SQLTRACE
    
    
    
    
    
    --(2)SQL CPU使用率并不是很高,小于50%
    --这是一种令人很头痛的现象,SQL的CPU使用率不高,常常是在30%~50%之间。SQL
    --也在运行,每秒钟甚至能够处理几百个批处理请求,但是用户反映,SQL没有正常
    --的时候那么快。这时候检查
    SELECT task_state FROM [sys].[dm_os_tasks]
    SELECT * FROM [sys].[dm_os_tasks]
    --state列,常常会发现很多任务的状态都是runnable
    
    --为什麽还有CPU资源,但是任务就是不能运行呢?这是因为SQL除了lock和latch以外
    --还有一种更轻量级的同步资源:spin lock(自旋锁) 在SQL里,有些很快就能得到
    --也很快会被释放,一般来讲不大会发生长时间等待的同步资源,SQL选择让线程在CPU
    --上稍微等一会(所谓自旋),而不是将CPU资源让出来。由于资源很快能够得到,这样
    --处理能够减少CPU上线程的切换,更有效率
    
    
    --像latch一样,spin是一种很轻量级的资源,正常情况下不应该成为SQL的瓶颈。
    --不过在SQL内部,自旋锁的种类还是挺多的。你可以运行下面语句,得到SQL
    --在所有自旋锁上等待的次数
    DBCC SQLPERF(spinlockstats)
    
    
    
    
    --(2)如果发现要访问的数据不在内存里,要将数据从磁盘读到内存中,如果发现内存里
    --没有足够的空闲页面存放所有数据,还要做一些内存整理和paging动作(换页动作)
    --腾出足够的空间放数据
    --这一步是挺花时间的。如果要访问的数据事先都缓存在内存里,这一步就不需要做了
    --可以省下大把时间,这就是为什麽有些语句第一次运行会比第二次运行慢很多的原因
    --也能解释为什麽一个内存资源不足的SQL性能有明显下降
    
    --在这一步的等待状态,通常是PAGEIOLATCH_X 。这时候也会观察到其他表明内存和磁盘
    --繁忙的现象
    
    --(3)按照执行计划,扫描或者seek内存中的数据页面,将指令需要处理的记录找出来
    --在这一步,SQL要申请各式各样的锁,以实现事务隔离。所以这个动作很容易遇到阻塞
    --问题。等待状态一般是以LCK_X开头的那些
    
    
    
    
    
    
    --(6)如果指令要修改数据记录,SQL会修改内存缓冲区里页面的内容
    --由于修改的对象是内存里的页面,在这一步不会直接触发磁盘写入,所以应该
    --不会直接导致磁盘瓶颈。但是如果有并发用户在修改同一个页面的时候,会出现
    --PAGELATCH_X的等待状态
    
    
    
    
    
    --TempDB上的PAGELATCH
    
    
    --分清楚数据库里面的数据页面和系统页面
    
    --需要解释的是,SQL不仅在数据页修改的时候加latch,在数据文件的系统页面上,例如
    --SGAM、PFS、GAM页面发生修改的时候,也会加latch。这些latch在某些情况下也有可能
    --成为系统瓶颈
    
    --例如:当数据库创建一张新表的时候,SQL要为这张表分配存储页面,同时SQL也要
    --修改SGAM、PFS、GAM页面,把已经分配出去的页面标志成已使用。所以每创建一张
    --新表,SGAM、PFS、GAM页面都会有修改动作
    
    --这种行为对一般用户数据库不会有问题,因为正常的应用不会折腾着不停地建表,删表
    --但是tempdb就不同了。如果一个存储过程使用了临时表,而这个存储过程被并发用户
    --广泛使用,那很自然地就会有很多并发用户在tempdb里同时创建表,做完了以后又
    --删除表。这时候在一个时间点,会有很多任务要修改SGAM、PFS、GAM页面。他们
    --上面的latch就会成为系统瓶颈。所以这类问题,通常会发生在tempdb上
    
    



    给我写信: QQ我:点击这里给我发消息



    2013年4月29日 13:55
  • --------------------------------------PAGEIOLATCH_x-------------------------------------------------------
    
    
    --pageiolatch_x与writelog
    --当缓存在内存缓冲区域里的数据页面,和磁盘上数据文件里的数据页面进行交互时,为了保证
    --不会有多个用户同时读取/修改内存里的数据页面,SQL会像对待表格里的数据一样,对内存中
    --的页面实行加锁机制,以同步多用户并发处理。不同的是,在这里,SQL加的是latch(轻量级的锁)
    --而不是lock
    
    
    --例如,当SQL将数据页面从数据文件里读入内存时,为了防止其他用户对内存里的同一个数据
    --页面进行访问,SQL会在内存的数据页面上加一个排他的latch。而当有任务要读缓存在内存
    --里的页面时,会申请一个共享的latch。像LOCK一样,latch也会出现阻塞的现象。根据不同
    --的等待资源,在SQL里等待的状态会是:
    
    --PAGEIOLATCH_DT:destroy buffer page io latch
    --PAGEIOLATCH_EX:exclusive buffer page io latch
    --PAGEIOLATCH_KP:keep buffer page io latch
    --PAGEIOLATCH_NL:null buffer page io latch
    --PAGEIOLATCH_SH:shared buffer page io latch
    --PAGEIOLATCH_UP:update buffer page io latch
    
    --这里举一个最容易发生的等待:PAGEIOLATCH_SH 来做例子,看看这种等待是怎麽发生的
    
    --有一个用户请求,必须读取整张X表,由worker x执行
    --worker x 在执行表扫描的过程中发现他要读取数据页面1:100
    --SQL发现页面1:100并不在内存中的数据缓存里
    --SQL在缓冲池里找到一个页面的空间,在上面申请一个EX的latch,以防止数据从磁盘
    --里读出来之前,有别人也来读取或修改这个页面
    
    --worker x发起一个异步IO请求,要求从数据文件里读出页面1:100
    --由于是个异步IO,worker x可以接着做他下面要做的事情。而下面要做的就是要读出内存中
    --的页面1:100。读取的动作需要申请一个SH的latch
    
    --由于worker x之前已经申请了一个EX latch还没释放,所以这个SH latch将被阻塞住。worker x
    --被自己阻塞住了,等待的资源就是PAGEIOLATCH_SH
    
    --当异步IO结束后,系统会通知worker x,你要的数据已经写入内存了
    
    --这时候EX latch就被释放。接着worker x得到了他申请的SH latch
    
    --数据页1:100 终于被worker x读到,读取工作结束,worker x可以继续下面的操作了
    
    --由此可以看到,在发生PAGEIOLATCH类型的等待时,SQL是在等待某个IO动作的完成。
    --所以如果一个SQL经常出现这一类的等待,说明磁盘的速度不能满足SQL的需要,
    --他已经成为了SQL的一个瓶颈
    
    
    
    
    --要强调的是,PAGEIOLATCH_x类型等待最常见的是两大类,PAGEIOLATCH_SH和
    --PAGEIOLATCH_EX。PAGEIOLATCH_SH经常发生在用户想要去访问一个数据页面
    --,而同时SQL却要把这个页面从磁盘读进内存。如果这个页面是用户经常有
    --可能访问到的,那么说到底,问题是因为内存不够大,没能够将数据页面
    --始终缓存在内存里。所以,往往是先有内存压力,触发SQL做了很多读取页面的工作
    --,才引发磁盘读的瓶颈。这里磁盘瓶颈常常是内存瓶颈的副产品
    
    
    --而PAGEIOLATCH_EX常常发生在用户对数据页面做了修改,SQL要向磁盘回写的时候,
    --基本意味着磁盘的写入速度明显跟不上。这里和内存瓶颈没有直接关系
    
    
    --和磁盘有关的另一个等待状态是WRITELOG,说明任务当前正在等待将日志记录写入日志文件
    --出现这个等待状态,也意味着磁盘的写入速度明显跟不上
    
    
    --和磁盘的写入速度有关的:PAGEIOLATCH_EX 和WRITELOG
    
    
    --------------------------PAGELATCH_x-----------------------------------------------------------
    
    --pagelatch_x类型是SQL在缓冲池里的数据页面上经常加的另一类latch
    --注意:pagelatch_x和pageiolatch_x是完全不一样的。因为长得像,
    --所以经常会被搞混。
    --PAGEIOLATCH_X出现在SQL要和磁盘进行交互的时候,所以中间有IO这两个字
    
    
    --PAGELATCH_X的作用:
    --先重复一下,每一行数据在数据页面里是怎麽存放的
    
    --每个SQL的数据页面大致分成3个部分:页头,页尾偏移量和数据存储部分。假设现在有一个表
    --结构是:
    CREATE TABLE test(
    a INT,
    b INT
    )
    
    --他在1:100这个页面上存储数据。那么这个页面结构大致如图
    --在页头部分,会记录页面属性,包括页面编号等,还会记录当前页面空闲部分
    --的起始位置在哪里
    
    --这样SQL在要插入新数据的时候,就能够很快地找到开始插入的位置,而页尾的偏移量
    --记录了每一条数据行的起始位置。这样SQL在找每一条记录的时候,就能很快找到
    --不会把前一条记录和后一条搞混。在图例这一页里现在有两条记录,(1,100)和(2,200)
    --第一条记录的开始位置是96,第二条记录的开始位置是111,从126开始,是空闲的空间
    
    --当页面里的数据行发生变化的时候,SQL不但要去修改数据本身,还要修改这些偏移量
    --的值,以保证SQL能够继续准确地管理数据页面里的每一行
    
    
    --现在假设有两个用户同时向这张表里插入数据,一个人插入(3,300),另一个人插入
    --(4,400)。SQL会为这两个插入语句各申请一个页面上的IX锁,防止有人将整个页面
    --改掉。两个IX锁是相互兼容的,所以这两条插入语句可以同时运行。在事务逻辑上
    --这两条语句插入的是两条不相干的记录,所以不应该相互阻塞,这样处理是正确的
    
    
    --但是到了物理存储这一层,问题就来了,这时候新的数据应该放在(2,200)后面,
    --也就是说,偏移量是126。可是该放谁呢?总不能两个值并列放吧?要想办法解决这个
    --冲突,一定要定义出一个先后顺序
    
    
    
    --SQL为了解决这类问题,引入了另一类页面上的latch:PAGELATCH。当一个任务要修改
    --页面时,他必须先申请一个EX的latch。只有得到这个latch,才能修改页面里的内容
    
    --所以这里的两个插入任务,不仅申请了页面上的锁,还要申请页面上的排他latch。假设
    --(3,300)这个插入任务先申请到了,那(4,400)这个任务就会被阻塞住。所以,(3,300)
    --这条记录能够被先插入
    
    --当(3,300)插入完成后,他申请的latch被释放。(4,400)就能得到latch资源,终于
    --轮到他做。(4,400)被插在了(3,300)的后面。这样,两个插入都正确地完成了
    
    --由于数据页的修改都是在内存中完成的,所以每次修改的时间都应该非常短,几乎可以
    --忽略不计。而pagelatch只是在修改的过程中才会出现,所以pagelatch的生存周期应该
    --也非常短。如果这个资源成为了SQL经常等待的资源,可以说明以下问题:
    
    --(1)SQL没有明显的内存和磁盘瓶颈(恭喜您!)
    
    --(2)应用程序发来大量的并发语句在修改同一张表格里的记录,而表格架构设计以及
    --用户业务逻辑使得这些修改都集中在同一个页面,或者数量不多的几个页面上。这些
    --页面有时候也被称为 hot page 热力页。这样的瓶颈通常只会发生在并发用户比较多
    --的,典型的OLTP系统上
    
    
    --如果有兴趣的话,可以做下面的实验,来体会一下HOT PAGE问题是什么样子:
    --(1)设置SQL 的最大线程数为350,以提高SQL的并发量(这里只是做实验,在
    --生产环境下这麽做可得做测试,以验证没有负面影响)
    
    EXEC [sys].[sp_configure] @configname = 'max worker threads', -- varchar(35)
        @configvalue = 350 -- int
    
    --(2)创建一个测试数据库TestDB。在里面创建一张以Identity为属性的列做聚集索引的表
    CREATE DATABASE TestDB
    GO
    USE TestDB
    GO
    CREATE TABLE TestTable
    (
      col1 INT IDENTITY(1,1) NOT NULL,
      col2 VARCHAR(50) NULL
    )
    GO
    
    CREATE UNIQUE CLUSTERED INDEX Idx1 ON [dbo].[TestTable]([col1])
    GO
    
    
    --col1列的属性是IDENTITY(1,1),决定了每一条插入的数据值,都会严格地以一递增。
    --上面又有一个聚集索引,数据行将按照这一列的值排序存放。这两个条件加在一起
    --,就意味着在一个时间点,只要页面当时还有空间,所有并发用户新插入的数据都
    --将被严格地先后插入在同一个页面里。
    
    
    
    --(3)用OSTRESS压力测试工具,模拟400个并发用户,每个用户要连续插入2000条记录
    
    
    --(4)这时候再去检查DMV SELECT * FROM sys.[dm_exec_requests],就可以看到PAGELATCH的等待状态了。
    
    --在现实环境里,可以试想下面情形。一个股票交易系统,每一笔交易都会有一个流水号
    --是递增而且不可重复的。而客户发过来的交易请求,都要存储在同一张交易表里。每一个
    --新的交易,都要插入一条新记录。如果设计者选择在流水号上建聚集索引(这也是很自然的)
    --就容易遇到HOT PAGE的PAGE LATCH资源瓶颈。在同一时间,只能有一个用户插入一笔交易
    
    
    
    
    
    


    给我写信: QQ我:点击这里给我发消息


    2013年4月29日 13:56
  • LZ应该说的是下面两个视图吧

    SELECT * FROM sys.[dm_os_latch_stats]
    SELECT * FROM [sys].[dm_os_wait_stats]


    [dm_os_wait_stats]这个视图里的wait_type指的是等待状态,因为sql里面的锁包含lock,latch,spin_lock这三种类型据我所知

    所以wait_type这个字段显示出来的锁等待状态包含了这三种锁类型

    而[dm_os_latch_stats]视图里面的latch_class字段包含的锁只是指latch类型的锁

    latch类型的锁比lock类型的锁更轻量级

    lathc大致分为:pageiolatch-X,pageiolatch-X,latch-X

    pageiolatch-X类型的锁存在于内存中的数据页的资源竞争

    pageiolatch-X类型跟磁盘交换数据的时候就会看到

    -------------------------------------华丽的分割线---------------------------------------------------------------

    latch_stats 中的buffer类型的 和 wait_stats 中的pagelatch 又有什么联系

    --(6)如果指令要修改数据记录,SQL会修改内存缓冲区里页面的内容
    --由于修改的对象是内存里的页面,在这一步不会直接触发磁盘写入,所以应该
    --不会直接导致磁盘瓶颈。但是如果有并发用户在修改同一个页面的时候,会出现
    --PAGELATCH_X的等待状态

    PAGELATCH-NL
    PAGELATCH-KP
    PAGELATCH-SH
    PAGELATCH-UP
    PAGELATCH-EX
    PAGELATCH-DT

    这些锁实际上某些意思跟lock类型的锁是一样的,像PAGELATCH-EX就是pagelatch类型的排他锁,PAGELATCH-UP就是更新锁


    给我写信: QQ我:点击这里给我发消息


    2013年4月29日 14:39
  • 还有一个,翻译的时候,一些文章会这样翻译

    闩锁=latch

    锁=lock


    给我写信: QQ我:点击这里给我发消息

    2013年4月30日 10:41
  • 还有一个,翻译的时候,一些文章会这样翻译

    闩锁=latch

    锁=lock


    给我写信: QQ我:点击这里给我发消息

    谢谢,我已经在 白皮书上找到答案了,latch 分为3中 1 buf latch 2 non buf latch 3 io latch  若是 非buf latch 则记录在 wait stats 的 latch_xx 中,buf latch 记录在 pagelatch中

    iolatch 记录在 pageiolatch中

    2013年5月3日 2:58
  • You can find details here: http://www.sqlskills.com/blogs/paul/wait-statistics-or-please-tell-me-where-it-hurts/.
    就是看了他的博文才出现这个疑问的,现在已经明白了谢谢
    2013年5月3日 2:59