sql server 性能调优 资源等待之 LCk

 一.  概述

  这次介绍实例级别资源等待LCK类型锁的等待时间,关于LCK锁的介绍可参考 “sql server 锁与事务拨云见日”。下面还是使用sys.dm_os_wait_stats 来查看,并找出耗时最高的LOK锁。

select wait_type,
waiting_tasks_count,
wait_time_ms ,
max_wait_time_ms,
signal_wait_time_ms
from sys.dm_os_wait_stats
where wait_type like 'LCK%' 
order by  wait_time_ms desc

 查出如下图所示:

太阳集团所有网址16877 1

   1.  分析介绍

   重点介绍几个耗时最高的锁含义:

    LCK_M_IX: 正在等待获取意向排它锁。在增删改查中都会有涉及到意向排它锁。
  LCK_M_U: 正在等待获取更新锁。 在修改删除都会有涉及到更新锁。
  LCK_M_S:正在等待获取共享锁。 主要是查询,修改删除也都会有涉及到共享锁。
  LCK_M_X:正在等待获取排它锁。在增删改中都会有涉及到排它锁。
  LCK_M_SCH_S:正在等待获取架构共享锁。防止其它用户修改如表结构。
  LCK_M_SCH_M:正在等待获取架构修改锁 如添加列或删除列 这个时候使用的架构修改锁。

      下面表格是统计分析

锁类型 锁等待次数 锁等待总时间(秒) 平均每次等待时间(毫秒) 最大等待时间
LCK_M_IX 26456 5846.871 221 47623
LCK_M_U 34725 425.081 12 6311
LCK_M_S 613 239.899 391 4938
LCK_M_X 4832 77.878 16 4684
LCK_M_SCH_S 397 77.832 196 6074
LCK_M_SCH_M 113 35.783 316 2268

  注意: wait_time_ms 时间里,该时间表包括了signal_wait_time_ms信号等待时间,也就是说wait_time_ms不仅包括了申请锁需要的等待时间,还包括了线程Runnable 的信号等待。通过这个结论也能得出max_wait_time_ms 最大等待时间不仅仅只是锁申请需要的等待时间。

 

2. 重现锁等待时间

--  重置
DBCC SQLPERF ('sys.dm_os_wait_stats', CLEAR);  

 太阳集团所有网址16877 2

--  会话1 更新SID=92525000, 未提交
begin tran 
update [dbo].[PUB_StockTestbak] set model='mmtest' where sid=92525000

-- 会话2 查询该ID, 由于会话1更新未提交 占用x锁,这里查询将阻塞
select * from [PUB_StockTestbak] where sid=92525000

   手动取消会话2的查询,占用时间是61秒,如下图:

太阳集团所有网址16877 3

  再来统计资源等待LCK,如下图 :

太阳集团所有网址16877 4

  总结:可以看出资源等待LCK的统计信息还是非常正确的。所以找出性能消耗最高的锁类型,去优化是很有必要。比较有针对性的解决阻塞问题。

3. 造成等待的现象和原因

现象:

  (1)  用户并发越问越多,性能越来越差。应用程序运行很慢。

  (2)  客户端经常收到错误 error 1222 已超过了锁请求超时时段。

  (3)  客户端经常收到错误 error 1205 死锁。

  (4)  某些特定的sql 不能及时返回应用端。

原因:

  (1) 用户并发访问越多,阻塞就会越来越多。

  (2) 没有合理使用索引,锁申请的数量多。

  (3) 共享锁没有使用nolock, 查询带来阻塞。 好处是必免脏读。

  (4) 处理的数据过大。比如:一次更新上千条,且并发多。

太阳集团所有网址16877,  (5) 没有选择合适的事务隔离级别,复杂的事务处理等。

4.  优化锁的等待时间

   在优化锁等待优化方面,有很多切入点 像前几篇中有介绍 CPU和I/O的耗时排查和处理方案。 我们也可以自己写sql来监听锁等待的sql 语句。能够知道哪个库,哪个表,哪条语句发生了阻塞等待,是谁阻塞了它,阻塞的时间。

  从上面的平均每次等待时间(毫秒),最大等待时间 作为参考可以设置一个阀值。 通过sys.sysprocesses 提供的信息来统计, 关于sys.sysprocesses使用可参考"sql server 性能调优 从用户会话状态分析"。 通过该视图 监听一段时间内的阻塞信息。可以设置每10秒跑一次监听语句,把阻塞与被阻塞存储下来。

   思想如下:

-- 例如 找出被阻塞会话ID 如时间上是2秒 以及谁阻塞了它的会话ID
SELECT spid,blocked #monitorlock FROM sys.sysprocesses 
where blocked>0 and    waittime>2000 

-- 通过while或游标来一行行获取临时表的 会话ID,阻塞ID,通过exec动态执行来获取sql语句文本 进行存储
exec('DBCC INPUTBUFFER(' @spid ')') 

exec('DBCC INPUTBUFFER(' @blocked ')') 

 

在今天的文章里,我想谈下在线索引重建操作( Online Index Rebuild operations),它们在SQL Server 2014里有怎样的提升。我们都知道,自SQL Server 2005开始引入了在线索引重建操作。但这些在线操作并非真正的在线操作,因为在操作开始时,SQL Server需要获得共享表锁(Shared Table Lock (S) ),在操作结束时需要在对应表上获得架构修改锁(Schema Modification Lock (Sch-M) )。因此这些操作是真正的在线操作,只是营销技巧(marketing trick)。但是,亲,“在线”肯定比“部分在线”好听多了。

尽管如此,SQL Server 2014还是在在线索引重建的开始和结束发生的阻塞做了一些改进。因此,在你执行在线索引重建时,你可以定义所谓的锁优先级(Lock Priority)。来看看下面的代码,你会看到起作用的新语法: 

 1 ALTER INDEX idx_Col1 ON Foo REBUILD
 2 WITH
 3 (
 4    ONLINE = ON
 5    (
 6       WAIT_AT_LOW_PRIORITY 
 7       (
 8          MAX_DURATION = 1, 
 9          ABORT_AFTER_WAIT = SELF
10       )
11    )
12 ) 
13 GO

当阻塞情况发生时,你可以用WAIT_AT_LOW_PRIORITY关键字定义如何处理。使用第1个属性MAX_DURATION指定你想要等待的时间——这里是分钟,不是秒!用ABORT_AFTER_WAIT属性你指定哪个会话需要被SQL Server回滚。SELF意味着那个ALTER INDEX REBUILD语句会回滚,当你指定BLOCKERS时,阻塞的会话会回滚。当然,当没有阻塞发生时,在线索引重建操作会立即执行。因此这里你只能配置当阻塞情况发生时要怎么处理。

好了,我们来实操下。我们新建一个数据库,一个简单的表和一个聚集索引。 

 1 -- Creates a new database
 2 CREATE DATABASE Test
 3 GO
 4 
 5 -- Use the database
 6 USE Test
 7 GO
 8 
 9 -- Create a simple table
10 CREATE TABLE Foo
11 (
12     Col1 INT IDENTITY(1, 1) NOT NULL,
13     Col2 INT NOT NULL,
14     Col3 INT NOT NULL
15 )
16 GO
17 
18 -- Create a unique Clustered Index on the table
19 CREATE UNIQUE CLUSTERED INDEX idx_Col1 ON Foo(Col1)
20 GO
21 
22 -- Insert a few test records
23 INSERT INTO Foo VALUES (1, 1), (2, 2), (3, 3)
24 GO

 为了触发阻塞,我在不同的会话开始一个新的事务,但不提交:

1 BEGIN TRANSACTION
2 
3 UPDATE Foo SET Col2 = 2
4 WHERE Col1 = 1

这意味着我们在需要修改的记录上获得排它锁(Exclusive Lock (X)),在对应的页上获得意向排它锁(Intent-Exclusive Lock (IX)),在表本身获得意向排它锁(Intent-Exclusive Lock (IX))。我们刚刚在SQL Server里创建了典型的锁定层次(locking hierarchy):表=>页=>记录。在表级别的意向排它锁(IX Lock)和在线索引重建操作需要的共享锁(Shared Lock)是不兼容的——典型的锁/阻塞情形发生了。当你现在执行在线索引重建操作时,会发生阻塞:

 

1 ALTER INDEX idx_Col1 ON Foo REBUILD
2 WITH
3 (
4    ONLINE = ON
5 )
6 GO

 

当你查看DMV sys.dm_tran_locks时,你会看到那个需要共享锁(Shared Lock(S))的会话需要等待。这个会话会永远等待。我刚才就说过:“部分在线”……

1 SELECT * FROM    sys.dm_tran_locks

太阳集团所有网址16877 5

当我们执行带有锁优先级(Lock Priority)的在线索引重建时,有趣的事情发生了: 

本文由太阳集团所有网址16877发布于太阳集团城网址送彩金,转载请注明出处:sql server 性能调优 资源等待之 LCk

您可能还会对下面的文章感兴趣: