SqlServer 表选项LOCK_ESCALATION对分区的影响

来源:互联网 发布:php curl 下载文件 编辑:程序博客网 时间:2024/06/15 10:06

http://blog.csdn.net/kk185800961/article/details/42774387


SqlServer 使用锁管理器跟踪数据库对象是否被锁住.通常一个查询将锁住一行或者一页,当锁超过一定范围之后,SqlServer尝试将锁升级为表锁来保证对内存的使用.锁升级有时会导致堵塞或者死锁.在SQL Server profiler中我们可以用[Lock:Escalation]事件来跟踪锁的升级.



在SQL Server 2005 中,可以使用跟踪标志 1211 来禁用整个实例中的锁升级.而在SQL Server 2008中,可以使用新的选择来禁止某个表的锁升级

ALTER TABLE SET (LOCK_ECALATION = AUTO | TABLE | DISABLE)


AUTO

此选项允许 SQL Server 数据库引擎选择适合于表架构的锁升级粒度。

(AUTO:如表已分区,将使用分区的hobt锁,但并发情况增加。)

如果该表已分区,则允许将锁升级到分区。 锁升级到分区级别之后,该锁以后将不会升级到 TABLE 粒度。

如果该表未分区,则会将锁升级到 TABLE 粒度

TABLE

无论表是否已分区,都会在表级粒度完成锁升级。 默认值为 TABLE

DISABLE

在大多数情况下禁止锁升级。 表级别的锁未完全禁止。

例如,当扫描在可序列化隔离级别下没有聚集索引的表时,数据库引擎必须使用表锁来保证数据的完整性。




经过几次插入数据测试,使我要更改的这个条件的数据达到6500行,这样才进行锁升级。否则键锁和页锁非常多。

[sql] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. --分区1:6500行  
  2. select COUNT(*) from dbo.AABB where $partition.pf_sid(sid)=1  

[sql] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. --先测试表:TABLE  
  2. ALTER TABLE dbo.AABB SET (LOCK_ESCALATION = TABLE);  

[sql] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. begin tran   
  2.     update dbo.AABB set num=1  
  3.     where sid=0x0105000000000005150000002B5CA2768377FDF37E993215F4010000  
  4.   
  5.     SELECT resource_type,resource_subtype,resource_description,request_mode,resource_associated_entity_id  
  6.     from sys.dm_tran_locks   
  7.     where resource_database_id=DB_ID() and request_session_id=@@SPID    
  8.     order by resource_type,resource_description  
  9. rollback tran  

可以看到,对象表使用了排他锁,这样整个表都不能访问了!


[sql] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. --再测试表:AUTO  
  2. ALTER TABLE dbo.AABB SET (LOCK_ESCALATION = AUTO);  


这才是正常的!!只锁定其中1个分区,其他分区还可以访问和修改!(关联的分区id不一样,因测试换了几次表)

当我们把表分区的时候,设置表选项 ALTER TABLE dbo.[tableName] SET (LOCK_ESCALATION = AUTO);这样可以在不同分区并行访问!


附加脚本:

[sql] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. --  查看分区情况    
  2. select OBJECT_NAME(object_id) as tab,COUNT(partition_number) as part       
  3. from sys.partitions       
  4. where index_id in(0,1)      
  5. and OBJECT_NAME(object_id) not like 'conflict%'      
  6. and OBJECT_NAME(object_id) not like 'sys%'      
  7. and OBJECT_NAME(object_id) not like 'MS%'     
  8. group by object_id   
  9. order by tab  
  10.   
  11.   
  12.     
  13. --  批量设置表选项——启用锁升级到分区    
  14. DECLARE @tbName VARCHAR(50)    
  15. DECLARE cur SCROLL CURSOR     
  16. FOR         
  17.     select OBJECT_NAME(object_id) as tab    
  18.     from sys.partitions       
  19.     where index_id in(0,1)      
  20.     and OBJECT_NAME(object_id) not like 'conflict%'      
  21.     and OBJECT_NAME(object_id) not like 'sys%'    
  22.     and OBJECT_NAME(object_id) not like 'MS%'    
  23.     group by object_id     
  24.     having COUNT(partition_number)>1    
  25.     order by tab    
  26. OPEN cur    
  27. FETCH NEXT FROM cur INTO @tbName    
  28. WHILE @@FETCH_STATUS = 0    
  29. BEGIN    
  30.     PRINT ('ALTER TABLE [dbo].['+@tbName+'] SET (LOCK_ESCALATION = AUTO); ')    
  31.     FETCH NEXT FROM cur INTO @tbName    
  32. END    
  33. CLOSE cur    
  34. DEALLOCATE cur    

附加说明:
触发锁升级:(数据库引擎不会将行锁或键范围锁升级到页锁,而是将它们直接升级到表锁)
A 单个 Transact-SQL 语句在单个无分区表或索引上获得至少 5,000 个锁
B 单个 Transact-SQL 语句在已分区表的单个分区上获得至少 5,000 个锁,并且 ALTER TABLE SET LOCK_ESCALATION 选项设为 AUTO
C 数据库引擎实例中的锁的数量超出了内存或配置阈值
D 如果由于锁冲突导致无法升级锁,则数据库引擎每当获取 1,250 个新锁时便会触发锁升级

0 0
原创粉丝点击