Latch是轻量级的锁,它是SQL Server内部用来同步资源访问的一个数据结构,使数据的访问同步有序,这意味着,当一个线程获得资源R的Latch的独占使用权时,如果其他的线程也想访问这个Latch时,那么它必须等待该Latch的独占使用权释放。
一,Latch介绍
Latch主要分为两种:Buffer Latch,I/O Latch,分别用于保护内存中的数据页和硬盘上的数据页。Latch的类型受到Buffer的一个比特的控制,bit:BUF_IO,该比特位表示Latch当前是否在做buffer的IO操作。当SQL Server从硬盘中读取一个Page时,会在Buffer Pool中预留一个Buffer(内存中的Page),并且为该Buffer的比特BUF_IO 设为1。如果Page从硬盘中读取,写入到Cache中,那么该bit设置为0。当BUF_IO=1时,对该Page申请的Latch是PageIOLatch;当BUF_IO=0时,对该Page申请的Latch是PageLatch。
我们先来简短介绍一下I/O Latch。当SQL Server从硬盘上读取一个页时,会先在内存预留该页的空间。并且在该预留空间的某一个位BUF_IO设为1。如果数据从硬盘读写完成,则该位设为0. 从硬盘读取页的期间,其他也需要访问该页的线程当然要等待,等待类型为PAGEIOLATCH_SH,直到读写完成,BUF_IO被设为0为止。另外一种Latch则称为Buffer Latch,用来保护内存里的数据结构,当进程需要读取一个内存里的数据页时,该进程要先获取该数据页上的Buffer Latch。
1,PageIOLatch
如果数据页不存在于Buffer Pool中,SQL Server必须从硬盘中把数据加载到内存,此时,SQL Server需要在Buffer Pool中预留一个Buffer,并为该Buffer申请一个PageIOLatch_EX,表示正在把数据页(Data Page)或索引叶(Index Page)加载到内存;如果数据页已经加载到内存,那么 PageIOLatch_EX 释放。在从硬盘读取到缓存的期间,需要访问该数据页的所有线程都需要等待,等待类型是:PageIOLatch_SH,如果我们看到大量PAGEIOLATCH_SH等待,则基本可以断定问题是出在磁盘性能上面。
PageIOLatch_EX 和 PageIOLatch_SH是不兼容的,直到Disk的读取过程完成,PageIOLatch_EX释放,线程申请到PageIOLatch_SH,表示数据页已经存在于Buffer Pool中。如果Disk IO缓慢,一个会话(Session)可能会对同一个Page同时申请PageIOLatch_EX 和 PageIOLatch_SH,自己把自己阻塞(block),毕竟请求数据写入的目的,就是为了读取数据。
SQL Server 从硬盘读取一个Page的过程如下:
- Acquires an EX latch on the page that does not exist in the buffer pool (EX mode: blocking others, and no duplicate same IO will be issued) 数据页不在内存中,SQL server 申请并得到该页的EX独占类型的latch。
- Issues the I/O request to read the page from disk 发出I/O请求,将该Page从Disk读取到Buffer pool。
- Tries to acquire another latch that has the shared (SH) latch mode on the same page. Because an EX latch has already been acquired, the SH latch request is blocked, and the SPID is suspended, so temporarily it seems the same SPID was blocking itself 试图在该页上面获得另外一个共享类型latch。因为该页的latch EX已经获得,而EX和SH不兼容,所以SH必须等待。看起来就像自己等待自己。
- When the I/O request finishes, the EX latch on the page is released 当页读取完毕,EX latch释放。
- Release of the EX latch gives the SH latch to the same thread 因为Latch EX 释放,Latch SH就成功获得。
- The thread can now read the page 现在该线程成功获得latch SH,可以读取该页了(该页已经在内存里面了)。
2,PageLatch
在访问数据库的数据页(Data Page或Index Page)时,如果相应的buffer已经存在于Buffer Pool中,那么SQL Server先获取buffer的latch,这个Latch就是 PageLatch,然后读取Buffer中的数据。
PageLatch是Buffer Latch, 用来保护内存中的数据结构,当进程需要读取一个内存里的数据页时,该进程要先获取该数据页上的Buffer Latch。
3,PageLatch和PageIOLatch都是加在内存page上的Latch
如果要读取数据库某一个数据页中的数据,那么这个数据页必须存在于内存中。如果不存在于内存中,SQL Server 发出一个IO请求,将该Page加载到内存中,然后从内存中读取该数据页中的数据。在数据读取的过程中,SQL Server创建Latch结构使该过程顺利进行。在访问一个Data Page之前,必须首先获取该page的Latch。如果Page不在内存中,获取的是PageIOLatch;如果page存在于内存中,获取的是PageLatch。
PageIOLatch_XX:当数据页不在内存里时,SQL Server 先在内存中预留一个Page,然后从Disk读取,加载到内存Page,此时,SQL Server申请并获取的latch类型是PAGEIOLATCH,PageIOLatch表示正在进行IO操作。PageIOLatch_EX表示正在将disk中的数据页加载到内存,PageIOLatch_SH表示在加载数据页到内存期间,试图读取内存中的数据页,此时加载数据页的过程没有完成,处于loading状态。如果经常出现PageIOLatch_SH,表明Loading数据页的时间太长,可能出现IO bottleneck。
PageLatch_XX:数据页已经存在于内存中,对内存数据页加的latch是PageLatch。此时从disk加载数据页的operation已经完成,处于Loaded状态,一个数据库page同时存在于内存和disk,在访问内存页之前,添加的latch,就是PageLatch。
----读后感 Buffer Latch Timeout的解析
IO Latch表示SQL Server正在将disk中的数据页加载到buffer Pool,一旦数据页加载完成,IO Latch就会释放。在加载数据页到buffer pool时,SQL Server Engine先在内存中预留一个page的空间,将位BUF_IO设置为1。内存中的Page,叫做Buffer。当BUF_IO=1时,对该Page加的Latch是PageIOLatch。当数据加载完成,该Page的位BUF_IO设置为0。当BUF_IO设置为0时,对该Page加的Latch是PageLatch。IO Latch和Buffer Latch都是对内存中的Page加的Latch,只不过,IOLatch是在Data Loading期间,BUF_IO位为1时,加在内存page上的latch;Buffer Latch是Data 加载完成, BUF_IO为0时,加在内存page上的latch。
当SQL Server从硬盘上读取一个页时,会先在内存预留该页的空间,并且将该预留空间的位BUF_IO设为1。如果数据从硬盘读写完成,则该位设为0。从硬盘读取页的期间,其他也需要访问该页的线程当然要等待,等待类型为PAGEIOLATCH_SH,直到读写完成,BUF_IO被设为0为止。因此,如果我们看到大量PAGEIOLATCH_SH等待,则基本可以断定问题是出在磁盘性能上面。
二,Latch和性能
1,数据的IO操作
SQL Server访问的任何一个Page必须存在于内存中,如果不存在于内存中,那么SQL Server发出 Disk IO请求,将数据页从Disk读取到内存中,然后SQL Server从内存中读取该Page的内容。在访问任何一个内存page之前,必须申请和获取该Page上的Latch。
在数据读取的过程中,SQL Server先在内存中预留一个Page的空间,并设置该Page的位BUF_IO=1,并发出Disk IO请求,此时,在该Page上加的Latch是PageIOLatch_EX,表示正在将数据页从Disk读取到内存。
在数据页加载的过程中,任何一个读取该Page的Thread,在该Page上加的Latch是PAGEIOLATCH_SH,表示在SQL Server Engine从Disk读取数据页,写入内存时,Thread试图读取该Page,由于PAGEIOLATCH_SH和PageIOLatch_EX不兼容,读取该Page的Thread会被Block,直到Page被读取到内存中。
一旦数据页被写入到内存中,PageIOLatch_EX会立即释放,并设置该Page的位BUF_IO=0。由于数据页存在于内存中,对该Page申请的Latch是PageLatch。
如果发生PAGEIOLATCH类型的等待,那么SQL Server一定是在等待Disk I/O操作的完成。如果经常出现这类等待,说明磁盘速度不能满足要求,已经成为SQL Server的瓶颈。PAGEIOLATCH_XX主要分为两大类:PAGEIOLATCH_SH和PAGEIOLATCH_EX。
PAGEIOLATCH_SH 发生在用户访问一个数据页,同时SQL Server正在将数据页从磁盘写入内存,经常发生PAGEIOLATCH_SH等待,说明内存不够大,导致SQL Server需要做很多页面读取的操作,磁盘IO是内存压力的副作用。
PAGEIOLATCH_EX:发生在从Disk page读取到内存buffer中,经常发生PAGEIOLATCH_EX等待,说明Disk读取速度慢,这和内存没直接关系。
2,数据页成为HotPage
当一个Task要修改页面时,它必须先申请一个EX的Latch,即PageLatch_EX。只有获取到Latch,才能修改页面的内容。由于数据页的修改都是在内存中完成,所以时间应该非常短,可以忽略不计。而PAGELATCH_EX只是在修改过程中才出现,所以生存周期应该很短,如果出现了,说明:1、SQL Server没有明显的内存和磁盘瓶颈。2、应用程序发出大量的并发语句修改同一张表,而修改操作集中在同一个页面,或者数量不多的几个页面上,成为Hot Page。3、这种瓶颈无法通过提高硬件配置解决,只能修改 Table的存储,使修改分散在更多的Page上,提高并发修改的能力。
Hot page的缓解方法:
(1)、换一个数据列建聚集索引,而不要在Identity字段上,同一时间插入有机会分散到不同的页面上。
(2)、如果一定要在Identity的字段上建聚集索引,建议在其他某个列上创建若干个分区。
(3)、为FileGroup增加File,尽量将Files分布在不同的Physical Disk上。
3,在tempdb中,系统Page成为Hot Page
SQL Server不仅在数据页面上加Latch,而且在数据文件的系统页面上,例如SGAM、PFS和GAM页面等,也会加Latch。系统Page有时候也会成为系统瓶颈。
在创建新表时,SQL Server 需要分配空间。分配存储空间需要同时修改SGAM、PFS和GAM页面,设置标识位,由于一个系统Page的标志位管理很多数据页,当频繁的创建和删除表结构时,而这些数据页都发生在同一个系统Page,或者数量不多的几个系统Page上,会使该系统Page过热,成为Hot Page。在tempdb中,创建和删除table结构的操作会并发、反复发生,容易使系统页过热,产生hot Page。系统page过热,可以通过调整表设计来缓解。对此的解决方法:
- 建立与cpu数量相同的tempdb文件,保持File Size相同,使得每个File承担的IO压力相对平均
- 禁止 tempdb 文件自动增长,避免单个文件不平均增长
引用《Q&A on Latches in the SQL Server Engine》:
Anytime you talk about latching and database pages, think in terms of BUF (buffer) latches. So to read a page from disk and put this into cache, the worker thread will take out a EX (Exclusive) latch on the BUF associated with the page. Then the read is issues for the page. Then a SH latch is taken out by this same thread on this BUF structure. Since these are not compatible, the thread will wait. Makes sense since we need to wait for the page to be read in from disk before trying to look at it. Any other thread needing to read this page will also wait since you need a SH latch on a BUF to read the page in cache. When the read has completed, the EX latch is released, and now the SH latch is acquired and the thread(s) can read the page in cache.
When a thread has to wait on a BUF latch, the engine will look at the BUF structure to see if a special bit is turned on called BUF_IO. This is set when a page associated with the BUF is currently being read from or written to disk. This is how the engine knows that if your thread is waiting on a latch, that it is waiting on an “IO Latch”. The wait_type will therefore look something like PAGEIOLATCH_SH as opposed to PAGELATCH_SH.
A latch is a short-term lightweight synchronization object. The following list describes the different types of latches:
- Non-buffer (Non-BUF) latch: The non-buffer latches provide synchronization services to in-memory data structures or provide re-entrancy protection for concurrency-sensitive code lines. These latches can be used for a variety of things, but they are not used to synchronize access to buffer pages.
- Buffer (BUF) latch: The buffer latches are used to synchronize access to BUF structures and their associated database pages. The typical buffer latching occurs during operations that require serialization on a buffer page, (during a page split or during the allocation of a new page, for example). These latches are not held for the duration of a transaction. These are indicated in the master.dbo.sysprocesses table by the PAGELATCH waittypes.
- IO latch: The IO latches are a subset of BUF latches that are used when the buffer and associated data page or the index page is in the middle of an IO operation. PAGEIOLATCH waittypes are used for disk-to-memory transfers and a significant waittime for these waittypes suggests disk I/O subsystem issues.
参考文档:
Q&A on Latches in the SQL Server Engine….
原文地址:https://www.cnblogs.com/littlewrong/p/9240170.html