主頁(yè) > 知識(shí)庫(kù) > 簡(jiǎn)單介紹SQL Server里的閂鎖

簡(jiǎn)單介紹SQL Server里的閂鎖

熱門標(biāo)簽:百度競(jìng)價(jià)排名 呼叫中心市場(chǎng)需求 網(wǎng)站排名優(yōu)化 AI電銷 服務(wù)外包 鐵路電話系統(tǒng) Linux服務(wù)器 地方門戶網(wǎng)站

在今天的文章里我想談下SQL Server使用的更高級(jí)的,輕量級(jí)的同步對(duì)象:閂鎖(Latch)。閂鎖是SQL Server存儲(chǔ)引擎使用輕量級(jí)同步對(duì)象,用來(lái)保護(hù)多線程訪問(wèn)內(nèi)存內(nèi)結(jié)構(gòu)。文章的第1部分我會(huì)介紹SQL Server里為什么需要閂鎖,在第2部分我會(huì)給你介紹各個(gè)閂鎖類型,還有你如何能對(duì)它們進(jìn)行故障排除。

為什么我們需要閂鎖?
閂鎖首次在SQL Server 7.0里引入,同時(shí)微軟首次引入了行級(jí)別鎖(row-level locking)。對(duì)于行級(jí)別鎖引入閂鎖的概念是非常重要的,不然的話在內(nèi)存中會(huì)出現(xiàn)丟失更新(Lost Updates)的現(xiàn)象。如我所說(shuō)的,閂鎖是存儲(chǔ)引擎使用的輕量級(jí)同步對(duì)象,是SQL Server用來(lái)保護(hù)內(nèi)存結(jié)構(gòu)的。閂鎖只不過(guò)是類似于多線程編程里的所謂的臨界區(qū)(Critcal Section)概念。

在傳統(tǒng)并發(fā)編程里,臨界區(qū)是同時(shí)只能一個(gè)線程運(yùn)行的代碼。閂鎖本身是個(gè)臨界區(qū)的特殊版本,因?yàn)樗试S多個(gè)并發(fā)讀操作。在SQL Server的上下文里這意味著多個(gè)線程可以并發(fā)讀取一個(gè)共享數(shù)據(jù)結(jié)構(gòu),例如內(nèi)存中的頁(yè),但是寫入共享數(shù)據(jù)結(jié)構(gòu)必須是單個(gè)線程進(jìn)行。

閂鎖是用來(lái)協(xié)調(diào)數(shù)據(jù)庫(kù)里多個(gè)線程物理執(zhí)行,然而鎖是基于選擇的事務(wù)隔離級(jí)別,用來(lái)邏輯獲得需要的隔離級(jí)別。作為開發(fā)者或DBA的你,你可以用不同方式影響鎖——例如通過(guò)SQL Server里的隔離級(jí)別,或者通過(guò)各種可用鎖提示。另一方面閂鎖是不能以直接方式控制的。在SQL Server里沒有閂鎖提示,也沒有可用閂鎖隔離級(jí)別。下表是鎖和閂鎖之間的比較:

                 鎖(Locks)         閂鎖(Latches)

控制……             事務(wù)              線程
保護(hù)……              數(shù)據(jù)庫(kù)內(nèi)容          內(nèi)存中數(shù)據(jù)結(jié)構(gòu)
模式……             共享的(Shared),      保持(Keep),
                 更新(Update),         共享的(Shared),

                 排它的(Exclusive),     更新(Update),排它的(Exclusive),

                 意向的(Intension)      銷毀(Destroy)

死鎖……           檢測(cè)并解決(detectionresolution)  通過(guò)嚴(yán)謹(jǐn)代碼來(lái)避免
保持在……  鎖管理器的哈希表(Hashtable)   保護(hù)的數(shù)據(jù)結(jié)構(gòu)(Protected Data Structure)
從表里可以看到,閂鎖支持更細(xì)粒度保持(Keep)和銷毀(Destroy)模式。保持閂鎖主要用來(lái)引用計(jì)數(shù),例如當(dāng)你想知道在指定閂鎖上有多少其它閂鎖在等待。銷毀閂鎖是最有限制的一個(gè)(它甚至?xí)枞3珠V鎖),當(dāng)閂鎖被銷毀時(shí)會(huì)用到,例如當(dāng)惰性寫入器(Lazy Writer)想要釋放內(nèi)存中的頁(yè)時(shí)。我們先介紹下各種閂鎖模式,然后說(shuō)下各個(gè)閂鎖模式的兼容性。

NL(空閂鎖):

                   內(nèi)部
                   未使用

KP(保持閂鎖):

                   可以由多個(gè)任務(wù)同時(shí)持有
                   只被一個(gè)DT模式的閂鎖阻塞

SH(共享閂鎖):

                  讀取數(shù)據(jù)頁(yè)的時(shí)候使用
                   可以由多個(gè)任務(wù)同事持有
                  阻塞EX模式和DT模式的閂鎖

UP(更新閂鎖):

                  寫入系統(tǒng)分配頁(yè)面和tempdb的行版本化頁(yè)面時(shí)使用
                 一個(gè)這種模式的閂鎖只能被一個(gè)單獨(dú)的任務(wù)持有

EX(排它閂鎖):

                   寫入數(shù)據(jù)頁(yè)的時(shí)候使用
                   一個(gè)這種模式的閂鎖只能被一個(gè)單獨(dú)的任務(wù)持有

DT(銷毀閂鎖):

                  很少使用
                  一個(gè)這種模式的閂鎖只能被一個(gè)單獨(dú)的任務(wù)持有

在SQL Server里,一致性不能只用鎖來(lái)獲得。SQL Server還是可以訪問(wèn)沒被鎖管理器保護(hù)的共享數(shù)據(jù)結(jié)構(gòu),例如頁(yè)頭。還有SQL Server基于閂鎖基礎(chǔ)的其他組件也是,有單線程代碼路徑。好了,我們繼續(xù)講解SQL Server里的各種閂鎖類型,還有如何對(duì)它們進(jìn)行故障排除。

閂鎖類型與故障排除
SQL Server區(qū)分3個(gè)不同閂鎖類別

                   IO閂鎖
                 緩沖區(qū)閂鎖(BUF)
                 非緩沖區(qū)閂鎖(Non-BUF)

我們來(lái)詳細(xì)看下這3個(gè)不同類別。當(dāng)在緩沖池的頁(yè)讀寫操作未完成——即當(dāng)你讀自/寫入你的存儲(chǔ)子系統(tǒng)時(shí)(2者未同步),SQL Server會(huì)使用IO閂鎖(I/O Latches)。對(duì)于這些I/O閂鎖,SQL Server在統(tǒng)計(jì)信息里以PAGEIOLATCH_為前綴出現(xiàn)。你可以在DMV sys.dm_os_wait_stats 查看下這些閂鎖類型的等待。

復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGEIOLATCH_%'

使用這些閂鎖,SQL Server保證那些頁(yè)不會(huì)并發(fā)多次讀入緩存池,那些頁(yè)也不會(huì)從緩存池忽略,在那些頁(yè)需要被查詢?cè)L問(wèn)的時(shí)候。

除這些I/O閂鎖外,SQL Server也支持所謂的緩存區(qū)閂鎖(Buffer Latches),它用來(lái)保護(hù)緩沖池里頁(yè)不會(huì)被并發(fā)運(yùn)行的線程影響。這些閂鎖,SQL Server使用它們來(lái)阻止內(nèi)存中的丟失更新(Lost Updates)。沒有這類閂鎖,在緩存池里會(huì)有并發(fā)的讀寫頁(yè),它們會(huì)引發(fā)主內(nèi)存里頁(yè)的損壞。對(duì)于這些緩存閂鎖,SQL Server在統(tǒng)計(jì)信息里以PAGELATCH_為前綴出現(xiàn)。你可以在DMV sys.dm_os_wait_stats 查看下這些閂鎖類型的等待。這里最重要的是你涉及了主內(nèi)存的競(jìng)爭(zhēng),因?yàn)樗麄兊牡却愋兔Q里不包含IO字樣。

復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGELATCH_%'

最后SQL Server內(nèi)部使用所謂的非緩存區(qū)閂鎖(Non-Buffer Latches)來(lái)保護(hù)除緩沖池外的共享數(shù)據(jù)結(jié)構(gòu)。對(duì)于這些非緩存閂鎖,SQL Server在統(tǒng)計(jì)信息里以LATCH_為前綴出現(xiàn)。你可以在DMV sys.dm_os_wait_stats 查看下這些閂鎖類型的等待。

復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'LATCH_%'

但在這個(gè)DMV里這些對(duì)于非緩存區(qū)閂鎖的等待只是SQL Server內(nèi)部使用的各個(gè)閂鎖的概況信息,你可以在單獨(dú)的DMV sys.dm_os_latch_stats找到更詳細(xì)的信息。

復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_latch_stats

SQL Server 2014內(nèi)部使用163個(gè)閂鎖來(lái)同步共享數(shù)據(jù)結(jié)構(gòu)的訪問(wèn)。其中一個(gè)著名的閂鎖是FGCB_ADD_REMOVE,它用來(lái)保護(hù)文件組的文件組控制阻塞( File Group Control Block (FGCB)),在以下特定操作期間:

        文件增長(zhǎng)(手動(dòng)或自動(dòng))
       增加/刪除文件組文件
       重新計(jì)算填充比重(Recalculating proportional fill weightings)
       在循環(huán)分配期間,通過(guò)文件組的文件回收。
當(dāng)你看到這個(gè)閂鎖排在前列是,你肯定有太多自動(dòng)增長(zhǎng)操作的問(wèn)題,原因是你數(shù)據(jù)庫(kù)糟糕的默認(rèn)配置。當(dāng)查詢嘗試讀/寫保護(hù)的數(shù)據(jù)結(jié)構(gòu)且需要等待一個(gè)閂鎖時(shí),查詢就會(huì)進(jìn)入掛起狀態(tài),直到閂鎖可以成功獲取。因此查詢經(jīng)過(guò)的整個(gè)查詢生命周期包括運(yùn)行(RUNNING),掛起(SUSPENDED),可運(yùn)行(RUNNABLE),最后再次運(yùn)行(RUNNING)。因此,當(dāng)查詢長(zhǎng)時(shí)間把持閂鎖時(shí),強(qiáng)制共享數(shù)據(jù)結(jié)構(gòu)保護(hù)才有意義。那是因?yàn)楦淖儾樵儬顟B(tài)也意味著進(jìn)行Windows系統(tǒng)里的上下文切換,依據(jù)引入的CPU周期是個(gè)很昂貴的操作。

因此對(duì)于讀寫頻繁或極短時(shí)間內(nèi)的共享數(shù)據(jù)結(jié)構(gòu)上放上閂鎖沒有意義。在這個(gè)情況下,需要的上下文切換會(huì)殺死SQL Server的整體性能,它需要花費(fèi)太多的時(shí)間來(lái)完成整個(gè)查詢生命周期(運(yùn)行(RUNNING),掛起(SUSPENDED),可運(yùn)行(RUNNABLE))。那就是是SQL Server引入的所謂自旋鎖(Spinlocks)。鎖管理器就是這樣數(shù)據(jù)結(jié)構(gòu)的好例子:當(dāng)鎖定或解鎖數(shù)據(jù)對(duì)象(例如記錄,頁(yè)等)時(shí)只需要單個(gè)線程訪問(wèn)。但當(dāng)你查看sys.dm_os_latch_stats時(shí),你會(huì)發(fā)現(xiàn)沒有閂鎖保護(hù)鎖管理器本身。鎖管理器使用的哈希表里對(duì)應(yīng)的哈希桶使用自旋鎖來(lái)保護(hù)——LOCK_HASH自旋鎖。通過(guò)鎖管理器執(zhí)行鎖定和解鎖操作前,必須獲得自旋鎖。

以上就是本文的全部?jī)?nèi)容,希望大家可以喜歡。

您可能感興趣的文章:
  • 淺析Sql server鎖,獨(dú)占鎖,共享鎖,更新鎖,樂(lè)觀鎖,悲觀鎖

標(biāo)簽:湘潭 仙桃 銅川 湖南 衡水 黃山 崇左 蘭州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《簡(jiǎn)單介紹SQL Server里的閂鎖》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266