简单介绍SQL Server里的闩锁 |
本文标签:SQL,闩锁 在今天的文章里我想谈下SQL Server使用的更高级的,轻量级的同步对象:闩锁(Latch) 。闩锁是SQL Server存储引擎使用轻量级同步对象,用来保护多线程访问内存内结构 。文章的第1部分我会介绍SQL Server里为什么需要闩锁,在第2部分我会给你介绍各个闩锁类型,还有你如何能对它们进行故障排除 。 为什么我们需要闩锁? 在传统并发编程里,临界区是同时只能一个线程运行的代码 。闩锁本身是个临界区的特殊版本,因为它允许多个并发读操作 。在SQL Server的上下文里这意味着多个线程可以并发读取一个共享数据结构,例如内存中的页,但是写入共享数据结构必须是单个线程进行 。 闩锁是用来协调数据库里多个线程物理执行,然而锁是基于选择的事务隔离级别,用来逻辑获得需要的隔离级别 。作为开发者或DBA的你,你可以用不同方式影响锁——例如通过SQL Server里的隔离级别,或者通过各种可用锁提示 。另一方面闩锁是不能以直接方式控制的 。在SQL Server里没有闩锁提示,也没有可用闩锁隔离级别 。下表是锁和闩锁之间的比较: 锁(Locks) 闩锁(Latches) 控制…… 事务 线程 排它的(Exclusive), 更新(Update),排它的(Exclusive), 意向的(Intension) 销毁(Destroy) 死锁…… 检测并解决(detection&resolution) 通过严谨代码来避免 NL(空闩锁): 内部 KP(保持闩锁): 可以由多个任务同时持有 SH(共享闩锁): 读取数据页的时候使用 UP(更新闩锁): 写入系统分配页面和tempdb的行版本化页面时使用 EX(排它闩锁): 写入数据页的时候使用 DT(销毁闩锁): 很少使用 在SQL Server里,一致性不能只用锁来获得 。SQL Server还是可以访问没被锁管理器保护的共享数据结构,例如页头 。还有SQL Server基于闩锁基础的其他组件也是,有单线程代码路径 。好了,我们继续讲解SQL Server里的各种闩锁类型,还有如何对它们进行故障排除 。 闩锁类型与故障排除 IO闩锁 我们来详细看下这3个不同类别 。当在缓冲池的页读写操作未完成——即当你读自/写入你的存储子系统时(2者未同步),SQL Server会使用IO闩锁(I/O Latches) 。对于这些I/O闩锁,SQL Server在统计信息里以PAGEIOLATCH_为前缀出现 。你可以在DMV sys.dm_os_wait_stats 查看下这些闩锁类型的等待 。 复制代码 代码如下: SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE PAGEIOLATCH_%
使用这些闩锁,SQL Server保证那些页不会并发多次读入缓存池,那些页也不会从缓存池忽略,在那些页需要被查询访问的时候 。 除这些I/O闩锁外,SQL Server也支持所谓的缓存区闩锁(Buffer Latches),它用来保护缓冲池里页不会被并发运行的线程影响 。这些闩锁,SQL Server使用它们来阻止内存中的丢失更新(Lost Updates) 。没有这类闩锁,在缓存池里会有并发的读写页,它们会引发主内存里页的损坏 。对于这些缓存闩锁,SQL Server在统计信息里以PAGELATCH_为前缀出现 。你可以在DMV sys.dm_os_wait_stats 查看下这些闩锁类型的等待 。这里最重要的是你涉及了主内存的竞争,因为他们的等待类型名称里不包含IO字样 。 复制代码 代码如下: SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE PAGELATCH_%
最后SQL Server内部使用所谓的非缓存区闩锁(Non-Buffer Latches)来保护除缓冲池外的共享数据结构 。对于这些非缓存闩锁,SQL Server在统计信息里以LATCH_为前缀出现 。你可以在DMV sys.dm_os_wait_stats 查看下这些闩锁类型的等待 。 复制代码 代码如下: SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE LATCH_%
但在这个DMV里这些对于非缓存区闩锁的等待只是SQL Server内部使用的各个闩锁的概况信息,你可以在单独的DMV sys.dm_os_latch_stats找到更详细的信息 。 复制代码 代码如下: SELECT * FROM sys.dm_os_latch_stats
SQL Server 2014内部使用163个闩锁来同步共享数据结构的访问 。其中一个著名的闩锁是FGCB_ADD_REMOVE,它用来保护文件组的文件组控制阻塞( File Group Control Block (FGCB)),在以下特定操作期间: 文件增长(手动或自动) 因此对于读写频繁或极短时间内的共享数据结构上放上闩锁没有意义 。在这个情况下,需要的上下文切换会杀死SQL Server的整体性能,它需要花费太多的时间来完成整个查询生命周期(运行(RUNNING),挂起(SUSPENDED),可运行(RUNNABLE)) 。那就是是SQL Server引入的所谓自旋锁(Spinlocks) 。锁管理器就是这样数据结构的好例子:当锁定或解锁数据对象(例如记录,页等)时只需要单个线程访问 。但当你查看sys.dm_os_latch_stats时,你会发现没有闩锁保护锁管理器本身 。锁管理器使用的哈希表里对应的哈希桶使用自旋锁来保护——LOCK_HASH自旋锁 。通过锁管理器执行锁定和解锁操作前,必须获得自旋锁 。 以上就是本文的全部内容,希望大家可以喜欢 。 |