PostgreSQL pg_locks

2021-09-14 15:02 更新

視圖pg_locks提供了數(shù)據(jù)庫服務(wù)器上活動(dòng)進(jìn)程中保持的鎖的信息。更多鎖的討論參見第 13 章。

pg_locks中對(duì)每一個(gè)活動(dòng)可鎖對(duì)象、請(qǐng)求鎖模式和相關(guān)進(jìn)程的組合都有一行。因此,如果多個(gè)進(jìn)程持有或者正在等待一個(gè)可鎖對(duì)象上的鎖,同一個(gè)可鎖對(duì)象可能出現(xiàn)很多次。但是,一個(gè)當(dāng)前沒有被鎖的對(duì)象根本不會(huì)出現(xiàn)。

有多種不同類型的可鎖對(duì)象:整個(gè)關(guān)系(如表)、關(guān)系的單個(gè)頁、關(guān)系的單個(gè)元組、事務(wù)ID(包括虛擬和永久ID)和普通數(shù)據(jù)庫對(duì)象(由類OID和對(duì)象OID標(biāo)識(shí),和pg_descriptionpg_depend中的相同方式)。 擴(kuò)展一個(gè)關(guān)系的權(quán)力也被表示為一個(gè)獨(dú)立的可鎖對(duì)象,就像更新pg_database. datfrozenxid的權(quán)力。advisory鎖可以具有用戶定義的意義。

表 51.74. pg_locks Columns

列類型

描述

locktype text

可鎖對(duì)象的類型: relation, extend, frozenid, page, tuple, transactionid, virtualxid, spectoken, object, userlock, or advisory. (參見 表 27.11.)

database oid (參考 pg_database.oid)

鎖目標(biāo)存在的數(shù)據(jù)庫的OID,如果目標(biāo)是一個(gè)共享對(duì)象則為0,如果目標(biāo)是一個(gè)事務(wù)ID則為空

relation oid (參考 pg_class.oid)

作為鎖目標(biāo)的關(guān)系的OID,如果目標(biāo)不是一個(gè)關(guān)系或者只是關(guān)系的一部分則此列為空

page int4

作為鎖目標(biāo)的頁在關(guān)系中的頁號(hào),如果目標(biāo)不是一個(gè)關(guān)系頁或元組則此列為空

tuple int2

作為鎖目標(biāo)的元組在頁中的元組號(hào),如果目標(biāo)不是一個(gè)元組則此列為空

virtualxid text

作為鎖目標(biāo)的事務(wù)虛擬ID,如果目標(biāo)不是一個(gè)虛擬事務(wù)ID則此列為空

transactionid xid

作為鎖目標(biāo)的事務(wù)ID,如果目標(biāo)不是一個(gè)事務(wù)ID則此列為空ID

classid oid (參考 pg_class.oid)

包含鎖目標(biāo)的系統(tǒng)目錄的OID,如果目標(biāo)不是一個(gè)普通數(shù)據(jù)庫對(duì)象則此列為空

objid oid (參考 any OID column)

鎖目標(biāo)在它的系統(tǒng)目錄中的OID,如果目標(biāo)不是一個(gè)普通數(shù)據(jù)庫對(duì)象則為空

objsubid int2

鎖的目標(biāo)列號(hào)(classidobjid指表本身),如果目標(biāo)是某種其他普通數(shù)據(jù)庫對(duì)象則此列為0,如果目標(biāo)不是一個(gè)普通數(shù)據(jù)庫對(duì)象則此列為空

virtualtransaction text

保持這個(gè)鎖或者正在等待這個(gè)鎖的事務(wù)的虛擬ID

pid int4

保持這個(gè)鎖或者正在等待這個(gè)鎖的服務(wù)器進(jìn)程的PID,如果此鎖被一個(gè)預(yù)備事務(wù)所持有則此列為空

mode text

此進(jìn)程已持有或者希望持有的鎖模式的名稱(參見第 13.3.1 節(jié)第 13.2.3 節(jié)

granted bool

如果鎖已授予則為真,如果鎖被等待則為假

fastpath bool

如果鎖通過快速路徑獲得則為真,通過主鎖表獲得則為假


一個(gè)行的granted為真表示一個(gè)被指定進(jìn)程持有的鎖。為假表示該進(jìn)程當(dāng)前正在等待獲取這個(gè)鎖,這意味著至少一個(gè)其他進(jìn)程正持有或等待同一個(gè)可鎖對(duì)象上的一個(gè)沖突鎖。該等待進(jìn)程將一直休眠直到其他鎖被釋放(或者一個(gè)死鎖狀態(tài)被檢測(cè)到)。單個(gè)進(jìn)程在同一時(shí)間只能等待最多一個(gè)鎖。

貫穿一個(gè)事務(wù)的運(yùn)行,一個(gè)服務(wù)器進(jìn)程在其生存周期內(nèi)都持有一個(gè)在其虛擬事務(wù)ID上的排他鎖。如果一個(gè)永久ID被分配給事務(wù)(通常發(fā)生在事務(wù)改變數(shù)據(jù)庫狀態(tài)時(shí)),它也會(huì)持有一個(gè)在其永久事務(wù)ID上的排他鎖直到它結(jié)束。當(dāng)一個(gè)事務(wù)發(fā)現(xiàn)它需要等待另一個(gè)事務(wù),它也會(huì)嘗試獲取其他事務(wù)ID上的共享鎖(不管是虛擬還是永久ID,視情況而定)。這只有當(dāng)其他進(jìn)程終止并釋放其鎖后才會(huì)成功。

盡管元組是一種可鎖對(duì)象,關(guān)于行級(jí)鎖的信息被存儲(chǔ)在磁盤而不是內(nèi)存中,因此行級(jí)鎖通常不在這個(gè)視圖中出現(xiàn)。如果一個(gè)進(jìn)程正在等待一個(gè)行級(jí)鎖,它通常在這個(gè)視圖中出現(xiàn),并且表示形式為正在等待已持有該行級(jí)鎖的永久事務(wù)ID上的鎖。

咨詢鎖可以在由一個(gè)單一bigint值或兩個(gè)整形值構(gòu)成的鍵上獲取。一個(gè)bigint鍵被顯示為其高位部分在classid列中,低位部分在objid列中,并且objsubid等于1。原來的bigint值可以使用表達(dá)式 (classid::bigint << 32) | objid::bigint重組。整形鍵被顯示為第一個(gè)鍵在classid列中,第二個(gè)鍵在objid列中,并且objsubid等于2。鍵的實(shí)際意義由用戶決定。咨詢鎖是每一個(gè)數(shù)據(jù)庫的本地鎖,所以database列對(duì)于一個(gè)咨詢鎖沒有意義。

pg_locks提供了一個(gè)對(duì)于整個(gè)數(shù)據(jù)集簇中所有鎖的全局視圖,而不僅僅是與當(dāng)前數(shù)據(jù)庫相關(guān)的鎖。盡管它的relation列可以被連接到pg_class.oid來標(biāo)識(shí)被鎖關(guān)系,但這種方法只有在關(guān)系屬于當(dāng)前數(shù)據(jù)庫(database列是當(dāng)前數(shù)據(jù)庫OID或者0的鎖對(duì)應(yīng)的關(guān)系)的情況下才會(huì)得到正確的結(jié)果。

pid列可以被連接到 pg_stat_activity視圖的pid列來得到持有或等待持有每一個(gè)鎖的會(huì)話的信息。 例如

SELECT * FROM pg_locks pl LEFT JOIN pg_stat_activity psa
    ON pl.pid = psa.pid;

另外,如果正在使用預(yù)備事務(wù),virtualtransaction列可以被連接到pg_prepared_xacts視圖的transaction列來得到持有該鎖的預(yù)備事務(wù)的信息(一個(gè)預(yù)備事務(wù)不可能正在等待一個(gè)鎖,但它在運(yùn)行中會(huì)一直持有已獲得的鎖)。 例如:

SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
    ON pl.virtualtransaction = '-1/' || ppx.transaction;

雖然通過自連接pg_locks可以獲得哪些進(jìn)程阻塞了其他哪些進(jìn)程的信息,但是很難得到其中的細(xì)節(jié)。這樣一個(gè)查詢隱藏了關(guān)于哪些鎖模式與其他哪些鎖模式?jīng)_突的知識(shí)。更糟糕的是,pg_locks視圖無法給出所等待隊(duì)列中進(jìn)程的等待順序,也無法顯示哪些進(jìn)程是代表其他客戶端會(huì)話運(yùn)行的并行工作者。更好的方法是使用pg_blocking_pids()函數(shù)(見 表 9.63)來標(biāo)識(shí)一個(gè)等待進(jìn)程是被哪些進(jìn)程阻塞的。

pg_locks視圖顯示來自于普通鎖管理器和謂詞鎖管理器的數(shù)據(jù),它們是獨(dú)立的系統(tǒng)。此外,普通鎖管理器把它的鎖分為普通鎖和快速路徑鎖。這些數(shù)據(jù)并不被保證是完全一致的。當(dāng)視圖被查詢時(shí),快速路徑鎖上的數(shù)據(jù)(fastpath = true)會(huì)被一次性從每一個(gè)后端收集起來,且并不凍結(jié)整個(gè)鎖管理器的狀態(tài)。因此有可能某些鎖在上述信息被收集的過程中被獲得或者釋放。注意,不管怎樣這些鎖是已知不會(huì)和任何當(dāng)前正在發(fā)生的鎖沖突。在所有后端已經(jīng)查詢了快速路徑鎖后,普通鎖管理器的剩余部分被作為一個(gè)單元鎖住,并且所有剩余鎖的一個(gè)一致快照被作為一個(gè)原子動(dòng)作收集。在解鎖普通鎖管理器后,謂詞鎖管理器也被類似地鎖住并且所有謂詞鎖被作為一個(gè)原子動(dòng)作收集。因此,在快速路徑鎖這種特殊情況下,每一個(gè)鎖管理器會(huì)傳遞一個(gè)一致的結(jié)果組。但由于我們并不會(huì)同時(shí)鎖上兩個(gè)鎖管理器, 在我們?cè)儐柾昶胀ㄦi管理器后或者詢問謂詞鎖管理器之前,鎖可以被獲得或者釋放。

如果對(duì)此視圖頻繁地訪問,對(duì)普通或者謂詞鎖管理器加鎖可能會(huì)對(duì)數(shù)據(jù)庫性能產(chǎn)生一定影響。雖然這些鎖只會(huì)在最少的時(shí)間內(nèi)被保持(足以從鎖管理器獲得數(shù)據(jù)),但這無法完全消除可能產(chǎn)生的性能影響。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)