如何识别和解决SQL Server中的热闩锁(PAGELATCH_EX)
描述
在SQL Server中,内部闩锁体系结构可在SQL操作期间保护内存。通过页面上的读写操作,可以确保内存结构的一致性。从根本上讲,它具有两个类:缓冲区锁存器和非缓冲区锁存器,它们在SQL Engine中执行轻量级同步。
闩锁确保内存一致性,而锁确保逻辑事务一致性。当多个用户或应用程序同时访问同一数据时,锁定会阻止他们同时更改数据。锁由Microsoft SQL Server Compact数据库引擎在内部进行管理。用户执行DML操作时,将自动获取锁并在资源上释放锁。锁存器可确保包括索引和数据页在内的存储器结构上的存储器一致性。通常,SQL Server使用缓冲池和IO锁存器来处理同步原始方式的内存结构。当服务器上有多线程并发负载时,由于尝试获取不兼容的内存结构而导致闩锁,并且这样做会导致闩锁争用 可能会出现问题。
SQL Server闩锁的类型很多,包括缓冲区,非缓冲区和IO闩锁。有关闩锁的更多说明,请查看这篇文章 。此外,我将详细讨论热闩锁,以及如何识别和解决它们。
锁存模式和兼容性
基本上,锁存器是在5种不同的模式下获取的:KP(保留锁存器),SH(共享锁存器),UP(更新锁存器),EX(排他锁存器),DT(销毁锁存器)。下面总结一下闩锁模式及其兼容性。
KP(保持闩锁)
保持闩锁可确保引用的结构不会被破坏。
SH(共享锁存器)
需要共享锁存器才能读取页面数据结构。共享锁存器(SH)与更新(UP)或保持(KP)锁存器兼容,但与销毁锁存器(DT)不兼容。
UP(更新锁存器)
更新锁存器与Keep锁存器和共享锁存器兼容,但是没有人可以写入其参考结构。
EX(专用锁存器)
此锁存器阻止其他线程等待或从参考区域读取。
DT(销毁闩锁)
销毁该内容之前,已将其分配给引用结构的内容。
与锁类似,所有这些锁存模式都存在兼容或者不兼容。例如,当线程尝试获取可能的闩锁且模式不兼容时,则将其放入队列中以等待资源可用。下面为闩锁模式兼容性表。
| 锁存器 | KP | SH | UP | EX | DT |
| KP | Y | Y | Y | Y | N |
| SH | Y | Y | Y | N | N |
| UP | Y | Y | N | N | N |
| EX | Y | N | N | N | N |
| DT | Y | N | N | N | N |
闩锁等待类型
对于并发负载,由于锁存模式不兼容,可能会导致页面争用。我们可以借助不同的SQL Server DMV的等待类型来找出这些争用问题。sys.dm_os_wait_stats,sys.dm_os_latch_stats,sys.dm_exec_query_stats等。
- 在DMV中以前缀PAGELATCH_ * 开头的缓冲区锁存器(BUF)。(例如PAGELATCH_EX,PAGELATCH_SH)
- 非缓冲锁存器(Non-BUF)在DMV中以前缀LATCH_ *开头。(例如LATCH_UP,LATCH_EX,LATCH_SH,LATCH_DT)
- IO闩锁带有前缀PAGEIOLATCH_ *。(例如PAGEIOLATCH_SH,PAGEIOLATCH_EX)
热锁(PAGELATCH_EX)
根据上述概述,由于这些锁存器争用而产生了不同的等待类型。在这些等待中,我将重点放在等待类型PAGELATCH_EX上。
此 等待类型表示当线程正在等待访问内存中的数据文件页面时,因为它可能是由于另一个正在运行的进程处于排他模式的页面结构。该结构将是表或索引的主页面。
通常,当通过插入操作在服务器上提高并发请求频率时,这些多个请求将在索引页上使用PAGELATCH_EX等待类型在同一资源上等待。这种情况也称为“热点问题”或“热点”。这种类型的闩锁争用在并发加载时通过更新或删除操作也是可能持有的。
对于此争用,可能是由于顺序的前导索引键导致了问题的产生。通常,建立索引是数据库性能的基础,但可能会引起争用。更具体地说,如果表具有聚簇索引,则在插入数据时会以排序的方式组织数据。尽管它在聚簇索引的末尾添加了一条记录,更直观地说问题出在页面拆分上。但是插入请求队列是在最后一页上生成的,除此之外,我们还可以在集群索引中添加一个标识列,这会导致其他性能问题,而单个对象上的并发插入频率更高。在并发插入时,这些请求如何堆积?图片中如何显示此闩锁争用PAGELATCH_EX?如需更多说明,请查看下图

如图所示,有多个请求将数据插入具有聚集索引的单个表中,因此这些请求在最后一页上等待,因为此插入语句是由物理顺序串行执行的,这种闩锁争用的结果是导致出现过多的PAGELATCH_EX等待。但是,此争用是指最后一页插入争用问题。
确定热闩锁争用问题
为了进一步说明,我将在本地服务器上重新创建此方案,为此,我准备了示例脚本。在脚本中,我介绍了一个基本表和过程以及一个数据库Hotspot。
样例脚本
CREATE DATABASE Hotspot
GO
Use Hotspot
GO
CREATE TABLE audit_Data
(
audit_id int primary key identity (1,1),
audit_action nvarchar(max),
audit_desc nvarchar(max),
ref_person_action int,
actionlist xml,
actionarea xml,
dtauditDate datetime default getdate ()
)
GO
CREATE PROCEDURE audit_history
(
@audit_action nvarchar(MAX),
@audit_desc nvarchar(max),
@ref_person_action int,
@actionlist xml,
@actionarea xml
)
as
begin insert into audit_Data
select @audit_action,@audit_desc,@ref_person_action,@actionlist,@actionarea,GETUTCDATE() select SCOPE_IDENTITY () end GO
在本地服务器上应用负载测试
测试服务器中有多种工具和实用程序可用于负载测试。我使用SQLQuerystress工具。
在此测试过程中,需要获取查询统计信息以解决此问题。出于演示目的,我准备了以下脚本以获取相关信息。
查询获取等待资源与T-SQL执行
我使用了多个SQL DMV,并在此基础上准备了用于获取等待统计信息的查询。另外,我们也可以使用分析器,活动监视器等工具。
SELECT wt.wait_duration_ms ,
wt.wait_type ,
s_text.text ,
DB_NAME(req.database_id) DatabaseName ,
req.wait_resource ,
session.login_name ,
req.last_wait_type
FROM sys.dm_os_waiting_tasks wt
INNER JOIN sys.dm_exec_requests req ON wt.session_id = req.session_id
INNER JOIN sys.dm_exec_sessions session ON session.session_id = req.session_id
CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) s_text
CROSS APPLY sys.dm_exec_query_plan(req.plan_handle) qp
WHERE session.is_user_process = 1;
查询测量的事务统计信息,闩锁等待,批处理请求等。
以下查询以获取锁存器,有关事务与时间的批处理请求。我在此查询中配置了30秒的延迟。
use Hotspot
go
select object_name,counter_name,cntr_value into #perfcounter
From sys.dm_os_performance_counters
where counter_name in
( 'Transactions/sec',
'Latch Waits/sec',
'Average Latch Wait Time (ms)',
'Batch Requests/sec')
and ( ltrim(rtrim(instance_name)) = 'HotSpot'
OR instance_name = '') WAITFOR DELAY '00:00:30'; select counters.object_name,counters.counter_name As ActionName,counters.cntr_value - perf.cntr_value ActionValue
From #perfcounter perf
inner join sys.dm_os_performance_counters counters on counters.counter_name = perf.counter_name
where counters.counter_name in
( 'Transactions/sec',
'Latch Waits/sec',
'Average Latch Wait Time (ms)',
'Batch Requests/sec')
and ( ltrim(rtrim(instance_name)) = 'HotSpot'
OR instance_name = '') DROP TABLE #perfcounter
GO
现在,我可以监视查询以及使用SQLQueryStress工具。现在,我将并行执行这两件事。
- 在本地,我配置了SQLQueryStress,然后应用过程负载100线程* 1000迭代。
- SSMS中都运行了两个监视查询。
SQLQueryStress使用100个线程* 1000次迭代加载测试结果.

在SSMS中监视查询结果
按照上面提到的监视查询,我将在两个不同的会话中执行。


可以看出,在监视查询结果中找到了多个等待类型PAGELATCH_EX的实例。
如何解决热闩锁争用
如果删除聚簇索引,可能可以减少争用,但这可能并不理想。我们有多种方式可以在整个索引范围内分配插入;水平分区技术,使用唯一键列中的哈希值等。
在前导唯一键列中使用哈希值
哈希值是指动态生成的键值。如果我在主键列中使用哈希值,则唯一键值将与audit_id一起分布在B树结构中。因此,我更改了表结构。出于演示目的,我将创建一个表和一个具有不同名称的过程,以下是我附加的脚本。
Use Hotspot
GO
CREATE TABLE audit_Data_with_Hashing
(
audit_id int identity (1,1) NOT NULL,
audit_action nvarchar(max),
audit_desc nvarchar(max),
ref_person_action int,
actionlist xml,
actionarea xml,
dtauditDate datetime default getdate (),
HashValue as (CONVERT([INT], abs([audit_id])%(30))) PERSISTED NOT NULL
)
GO ALTER TABLE audit_Data_with_Hashing
ADD CONSTRAINT pk_hashvalue
PRIMARY KEY CLUSTERED (HashValue, audit_id) --HashValue
GO CREATE PROCEDURE audit_history_with_Hashing ( @audit_action nvarchar(MAX), @audit_desc nvarchar(max), @ref_person_action int, @actionlist xml, @actionarea xml ) as begin insert into audit_Data_with_Hashing select @audit_action,@audit_desc,@ref_person_action,@actionlist,@actionarea,GETUTCDATE() select SCOPE_IDENTITY () end GO
我已经在测试服务器中应用了上述脚本,现在我将应用与以前相同的负载测试并再次捕获统计信息。
具有100个线程* 1000次迭代的SQLQueryStress负载测试结果
我已经重新运行SQLQueryStress工具并执行如下。

在SSMS中监视查询结果
根据前面提到的监视查询,我将在两个不同的会话中执行。


现在,我在30秒内获得了负载测试结果,锁存等待/秒为484,而不是196,746,平均锁存等待时间(MS)数为 206,170,而不是1,421,675。作为查询统计信息的结果,减少了Pagelatch_EX等待。根据用例,这种方法可能会有不同的效果。下面将描述其优缺点。
分区技术
当一个表具有数百万行时,进行DML操作。在这种情况下,需要像垂直和水平表级别分区一样更改结构级别。这些之间需要权衡取舍。水平表分区可以轻松集成。我们还可以在计算列上应用水平分区,该功能几乎与使用领先的唯一索引具有相同的功能,只是差别很小。执行插入操作时,此操作仍在此逻辑范围的末尾,但是哈希值会生成动态值,并且会在B树结构中进行拆分。这样做可能是有可能减少争用,因为可以使用计算列来解决此频率插入争用问题。
结论
我已经总结了要点,并在下面提到了权衡问题。
优点
- 使用聚簇索引,插入将以非顺序的方式执行,并且可以防止闩锁争用问题的发生。
- 表分区功能对于管理大量数据非常有用。
缺点
- 索引键长度大于正常值。由于索引大小的差异和页面遍历的成本,碎片化可能成为一个问题。
- 随机插入操作可能会生成分页操作。
- 如选择查询之类的获取数据操作可能会在从哈希分区检索数据时产生问题,因为查询计划的估计可能不准确。
- 增加索引的键组合时,很难保持引用完整性。
如何识别和解决SQL Server中的热闩锁(PAGELATCH_EX)的更多相关文章
- 【转】SQL Server中的事务与锁
SQL Server中的事务与锁 了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂 ...
- 如何解决 SQL Server 中的锁升级所致的阻塞问题
概要 锁升级为表锁插入转换很多细粒度的锁 (如行或页锁) 的过程.Microsoft SQL Server 动态确定何时执行锁升级.作出决定之前,SQL Server 将特定的扫描,整个事务,并且用于 ...
- 解决SQL Server中无管理员账户权限问题
遇到忘记SQL Server管理员账户密码或管理员账户被意外删除的情况,如何在SQL Server中添加一个新的管理员账户?按一下步骤操作可添加一个windows账户到SQL Server中,并分配数 ...
- SQL Server中的事务与锁
了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...
- [转载]SQL Server中的事务与锁
了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不能保证数据的安全正确读写. 死锁: ...
- T-SQL查询进阶--SQL Server中的事务与锁
为什么需要锁 在任何多用户的数据库中,必须有一套用于数据修改的一致的规则,当两个不同的进程试图同时修改同一份数据时,数据库管理系统(DBMS)负责解决它们之间潜在的冲突.任何关系数据库必须支持事务的A ...
- 十五、SQL Server中的事务与锁
(转载别人的内容,值得Mark) 了解事务和锁 事务:保持逻辑数据一致性与可恢复性,必不可少的利器. 锁:多用户访问同一数据库资源时,对访问的先后次序权限管理的一种机制,没有他事务或许将会一塌糊涂,不 ...
- SQL Server中CURD语句的锁流程分析
我只在数据库选项已开启“行版本控制的已提交读”(READ_COMMITTED_SNAPSHOT为ON)中进行了观察. 因此只适用于这种环境的数据库. 该类数据库支持四种不同事务隔离级别,下面分别观察数 ...
- SQL Server 中 ROWLOCK 行级锁
一.ROWLOCK的使用 1.ROWLOCK行级锁确保,在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改.因而行级锁即可保证数据的一致性,又能提高数据操作的并发性. 2.ROWLOC ...
随机推荐
- 转发:for /f命令之—Delims和Tokens用法&总结
在For命令语踞饽参数F中,最难理解的就是Delims和Tokens两个选项,本文简单的做一个比较和总拮.“For /f”常用来解析文本,读取字符串.分工上,delims负责切分字符串,而tokens ...
- 33 Eclipse无法查看源码解决
问题如图 点击 Attach Source 解决方法 下载src.zip包,src包地址:https://pan.baidu.com/s/1oAqqqHO 选择此src包即可
- day41——数值类型、完整性约束
day41 数值类型 整数类型 有符号的设置 mysql> create table t1(id tinyint); # 默认有符号,即数字前有正负号 无符号的设置 mysql> crea ...
- mysql 免费的图形管理工具
在学习go语言开发时,使用了mysql 使用了两天mysql命令行,感觉实在是无法忍受, 找到了一个免费好用的 图形数据库管理工具SQLyog Professional 版本: 注册名:luoye25 ...
- 关于django操作orm的一些事--反向生成orm、连接多个数据库
1. django反向生成orm的类代码 使用命令python manage.py inspectdb > app01/models.py,注意,我这里的app01是app的名字. 2.djan ...
- html2canvas以及domtoimage的使用踩坑总结 动态获取的二维码失效如何生成海报
//判断手机为安卓还是ios 安卓html2canvas方法 ios系统dom-to-image方法 $(".code").click(function() { var u = n ...
- sql 作业创建
转载:https://jingyan.baidu.com/article/adc81513be3423f722bf7351.html
- C# vb .net实现对比度调整特效滤镜效果
在.net中,如何简单快捷地实现Photoshop滤镜组中的对比度效果呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第一 ...
- String字符串创建方法
String字符串的创建方法我们总结为3+1,3是一共有3种构造方法,1是有一种特殊的创建方法. 首先来看3种构造方法: 1.new String() 无参构造 用该方法创建的字符串是一个空字符串, ...
- ColdFusion 编写WebService 示例
1.开发 Web Services,编写cfcdemo.cfc组件,代码如下: <cfcomponent style ="document" namespace = &quo ...