SQL Server 性能调优(一)——从等待状态判断系统资源瓶颈【转】

时间:2021-09-28 16:06:43

转载自:http://blog.csdn.net/dba_huangzj/article/details/7607844#comments

通过DMV查看当时SQL SERVER所有任务的状态(sleeping、runnable或running)

2005、2008提供了以下三个视图工详细查询:

DMV

用处

Sys.dm_exec_requests

返回有关在SQL Server中执行的每个请求的信息,包括当前的等待状态

Sys.dm_exec_sessions

对于每个通过身份验证的会话都返回相应的一行。此时图是服务器范围的视图。此视图首先可以查到服务器负荷

Sys.dm_exec_connections

返回与SQL Server 实例建立的连接有关的信息以及每个连接的详细信息

Sys.sysprocesses是为了向后兼容,所以建议使用以上3个DMV。

另外还有一个DMV:sys.dm_os_wait_stats可以返回从SQL Server启动以来所有等待状态的等待数和等待时间。是个累积值。

SQL Server 性能调优(一)——从等待状态判断系统资源瓶颈【转】

1、  LCK_XX类型:

如果SQL Server经常有阻塞发生,会经常看到以“LCK_”开头的等待状态:

等待状态

说明

LCK_M_BU

正在等待获取大容量更新锁(BU)

LCK_M_IS

等待获取意向共享锁(IS)

LCK_M_IU

等待获取意向更新锁(IU)

LCK_M_IX

等待意向排它锁(IX)

LCK_M_RIn_NL

等待获取当前键值上的NULL锁以及当前剪和上一个键之间的插入范围锁

LCK_M_RIn_S

等待获取当前键值上的共享锁以及当前键和上一个键之间的插入范围锁

LCK_M_RIn_U

等待获取当前键值上的更新锁以及当前键和上一个键之间的插入范围锁

LCK_M_RIn_X

等待获取当前键值上的排他锁以及当前键和上一个键之间的插入范围锁

LCK_M_RS_S

等待获取当前键值上的共享锁以及当前键和上一个键之间的共享范围锁

LCK_M_RS_U

等待获取当前键值上的更新锁以及当前键和上一个键之间的共享范围锁

LCK_M_RX_S

等待获取当前键值上的共享锁以及当前键和上一个键之间的排他范围锁

LCK_M_RX_S

等待获取当前键值上的共享锁以及当前键和上一个键之间的排他范围锁

LCK_M_RX_U

等待获取当前键值上的更新锁以及当前键和上一个键之间的排他范围锁

LCK_M_RX_X

等待获取当前键值上的排他锁以及当前键和上一个键之间的排他范围锁

LCK_M_S

等待获取共享锁

LCK_M_SCH_M

等待架构修改锁

LCK_M_SCH_S

等待获取架构共享锁

LCK_M_SIU

等待共享意向更新锁

LCK_M_SIX

等待获取共享意向排他锁

LCK_M_U

等待更新锁

LCK_M_UIX

等待更新意向排他锁

LCK_M_X

等待排他锁

2、  PAGEIOLATCH_X与WRITELOG:

在缓存池中的数据页面,为了同步多用户并发,SQL Server会对内存的页面加锁。不同的是,加的是latch(轻量级的锁),而不是lock。

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

PAGEIOLATCH_X最常见的分两大类:PAGEIOLATCH_SH和PAGEIOLATCH_EX,PAGEIOLATCH_SH:经常发生在用户正想要访问一个数据页面,而同时SQL Server却要把页面从磁盘读往内存。说明内存不够大,触发了SQL Server做了很多读取页面的工作,引发了磁盘读的瓶颈。此时是内存有瓶颈。磁盘只是内存压力的副产品。

PAGEIOLATCH_EX:经常发生在用户对数据页面做了修改。SQL Server要向磁盘回写的时候。意味着写的速度跟不上。这和内存没直接关系。

WRITELOG:和磁盘有关的另一个等待状态,正在等待写日志记录,意味着写入速度也明显跟不上。

3、  PAGELATCH_X:SQLServer为了解决在插入数据时,到了物理层的插入冲突,所以引入了另一类页面上的latch:PAGELATCH,当一个任务要修改页面时,它必须先申请一个EX的latch。只有得到这个,才能修改页面的内容。由于数据页的修改都是在内存中完成,所以时间应该非常短,可以忽略不计。而PAGELATCH只是在修改过程中才出现,所以生存周期应该很短,如果出现了,说明:1、SQLServer没有明显的内存和磁盘瓶颈。2、应用程序发来大量的并发语句在修改同一张表。而设计及用户业务逻辑使得这些修改都集中在同一个页面,或者数量不多的几个页面,成为Hot Page,通常在OLTP系统上出现比较多。3、这种瓶颈无法通过提高硬件配置解决,只能通过修改表设计或者业务逻辑,让修改分散,提高并发性。

对于Hot page的缓解方法:

(1)、换一个数据列建聚集索引,而不要在Identity的字段上,同一时间插入有机会分散到不同的页面上。

(2)、如果一定要在Identity的字段上建聚集索引,建议在其他某个列上建若干个分区。

4、  Tempdb上的PAGELATCH:

数据库不仅在数据页面修改的时候加latch,在数据文件的系统页面上,例如SGAM、PFS和GAM页面发生修改的时候,也会加latch。有时候也会成为系统瓶颈。

在创建新表需要分配空间时,SQLServer同时要修改SGAM、PFS和GAM页面,把已分配的页面标志成已使用,所以这些页面都会有所修改。但在tempdb中,这种操作会并发、反复。数据页的hot能通过调整表设计来缓解。对此的解决方法:

1、  建立与cpu数量相同的tempdb文件,并且大小要相同,这样能平均分配压力。

2、  严格防止tempdb空间用尽。防止自动增长时把其中一个文件增长,破坏平均分配。

3、  可以使用sp_helpfile来查看文件信息。

5、  其他资源等待:

1、  LATCH_X:

(1)、某个先前的任务出现了访问越界异常,SQLServer强制终止了任务,但是没有完全将它申请的资源释放干净。使其成为孤儿。后面的资源就被阻塞。只要打开SQLServer日志文件(errorlog),看看有没有出现过Access Violation问题,但是一般无法从用户层面一般无法解决,只有重启服务器才能解决。

(2)、同时发生其他资源瓶颈,如内存、线程调用、磁盘等,而latch等待只是一个衍生的等待。

(3)、当某个数据文件空间用尽,做自动增长的时候,同一个时间点只能有一个用户任务可以做文件自动增长动作,其他任务必须等待。

(4)、在一些特殊情况下,有可能是SQLServer自己没有处理好并发同步,没有使用比较优化的算法,使得用户比较容易遇到等待,一些补丁就曾修复过这类问题。

一般等待都是由其他问题衍生出来,首先要检查SQLServer是否健康运行。是否有出现过任何异常。是否有其他资源瓶颈。

2、  ASYNC_NETWORK_IO(NETWORK_IO:2000的叫法):

此等待状态出现在SQLServer已经把数据准备好,但是网络没有足够的发送速度跟上,所以SQLServer的数据没地方存放。

(1)      出现这种情况一般不是数据库的问题,调整数据库配置不会有大的帮助。

(2)      网络层的瓶颈当然是一个可能的原因:对此要考虑是否真有必要返回那么多数据?

(3)      应用程序端的性能问题,也会导致SQLServer里的ASYNC_NETWORK_IO等待。如果见到了这个类型的等待,就要检查应用程序的健康状况,也要检查应用是否有必要想SQLServer申请这么大的结果集。

3、  和内存有关的等待状态:

当用户任务申请内存暂时申请不到的时候,会出现一些特殊的等待状态:

COEMTHREAD/SOS_RESERVEDMEMBLOCKLIST/RESOURCE_SEMAPHORE_QUERY_COMPLIE

如果在DMV上看到这些状态,就要确认SQLServer是否存在内存瓶颈。

4、  SQLTRACE_X:

对于繁忙的SQLServer,开启SQL Trace会产生负面影响。如果出现这种等待,除非迫不得已,不然应该立刻停止搜集SQL Trace

6、  最后一道瓶颈:许多任务处于runnable状态:

如果出现这种状态,证明很多任务可以运行但没在运行。

Sys.dm_exec_requests/sys.sysprocesses的status列,反映了当前所有任务的状态,如果看到好多状态是runnable,那就要严肃对待,正常的SQLServer哪怕非常忙,也不应该经常看到runnable,连running的状态都不应该很多。

如果没有报17883/17884之类的警告,出现非常多的runnable任务可能有两种原因:

(1)、SQLServer CPU使用率接近100%,真的没有足够的cpu来及时处理用户的并发任务。此时应该优化最耗CPU资源的语句或者应用,或者加CPU

(2)、SQLServer CPU使用率并不高,小于50%。这时检查sys.dm_exec_requests的task_state列,会发现很多runnable状态。因为SQLServer除了lock和latch之外,还有一种更轻量级的同步资源:spin lock(自旋锁)。自旋:一些不会发生长时间等待的同步资源,SQLServer会选择让线程在cpu上稍微等待一下,而不会将cpu资源让出来。

可以使用DBCC SQLPERF(SPINLOCKSTATS)查看。

在2005上的64位SQLServer,当内存比较充裕时,会缓存很多执行计划,同事缓存很多执行计划安全上下文。在memory clerk里,用TokenAndPermUserStore表示,当这段内存比较大时,并发用户会容易遇到一种叫MUTEX的自旋锁。可以参考:http://suppot.microsoft.com/kb/927396。这种问题只在安全上下文缓存得太多时才容易发生,所以定期执行一下以下语句有效防止,而且对系统整体性能也没什么坏的影响:

DBCC FREESYSTEMCACHE(TokenAndPermUserStore)

也可以以-T4618和-T4610启动SQLServer,让SQLServer使用另一种缓存管理机制。

据说2008已经改进,不容易出现自旋锁。

7、  小结:

用户请求的什么周期:

1、  客户端向SQLServer发出请求指令,经过网络层,SQLServer接收到。

在这一步中,如果指令比较长,或者比较多,会影响SQLServer接受的速度。

2、  SQLServer对收到的指令进行语法、语义检查,编译,生成新的执行计划,或者找到缓存的计划重用:这一步耗费资源的种类比较多:

l  CPU:做检查、编译、生成计划都需要计算,这一步耗费CPU资源比较多,尤其是指令复杂的时候。

l  内存:对于非常长的IN子句或者由几万、几十万语句组成,要花费非常大的内存,主要使用stolen内存,对于32位系统来说是很紧张的。一般会出现这些等待情况:CMEMTHREAD/SOS_RESERVEDMEMBLOCKLIST/RESOURCE_SEMAPHORE_QUERY_COMPILE,或者701错误。

l  表上的架构锁(schema lock):在编译时,要防止对该架构进行修改。如果并发很高,那么会产生阻塞。

l  在SQLServer确认是否有线程的执行计划可用时,要在内存中进行搜索。可能会产生自旋锁。

3、  运行指令:

在等到执行计划之后,就进入运行阶段,用到的资源最多。在这一步要做很多事情:

(1) 、SQLServer首先为指令的运行申请内存。

如果同时需要执行很多指令,可能会在内存上遇到困难,通常会见到:RESOURCE_SEMAPHORE_开头的等待状态。

(2) 、如果发现要访问的数据不在内存中。

要讲数据从磁盘读到内存,如果发现内存没有足够的空闲页面存放所有数据,还要做内存整理和paging动作,腾出足够的空间放数据。通常简单的等待状态是:PAGEIOLATCH_X。

(3) 、按执行计划,扫描或者seek内存中的数据页面,讲执行需要处理的记录找出来。这一步需要申请各种各样的锁,以实现事务隔离。通常会引起阻塞,以LCK_开头的那些。

(4) 、指令可能还要做一些连接或者计算工作(sum、max、sort等)

这一步主要使用CPU。

(5) 、根据指令内容、执行计划和数据量,SQLServer可能还会在tempdb创建一些对象,存放临时表、表变量,帮助做join、sort等。

此时有可能出现tempdb瓶颈。

(6) 、如果指令需要修改数据记录,SQLServer会修改内存缓冲区里的页面内容。

由于对象在内存中,不会触发磁盘写入,但由于修改同一页面,容易导致PAGELATCH_X的等待状态。

(7) 、如果指令发生数据修改,在提交事务之前,SQLServer必须将相应的日志记录按照顺序写入日志文件。如果瞬间日志量太大,会出现WRITELOG的等待状态。

(8) 、将结果集返回给客户端:得到结果后,SQLServer会把结果集放到输出缓存中,等客户端把结果集全部取走。指令才结束。如果数据集太大,会导致网络交互太多。此时容易出现:ASYNC_NETWORK_IO等待状态。

以上的动作都要在SQLOS中首先得到一个Worker/thread,然后还要排上scheduler,在CPU上运行。

l  SQLServer所有的Worker都在忙自己的事情,就会等待,可以看到等待状态是0x46(UMSTHREAD)。而sys.dm_os_schedulers.work_queue_count的值会不等于0

l  成功拿到worker,但在scheduler又要等待其他Worker,这时看到状态是runnable,而sys.dm_os_schedulers.runnable_tasks_count>1。

l  拿到scheduler,进入running状态,如果非常耗CPU,会出现cpu使用率高的现象。

l  遇到性能问题,查看sys.dm_exec_requests这类DMV对找到问题很有帮助。