51.73. pg_locks

视图pg_locks提供对有关数据库服务器内活动进程所持有的锁的信息的访问。有关锁定的更多讨论,请参见Chapter 13

pg_locks每个活动的可锁定对象,请求的锁定模式和相关过程包含一行。因此,如果多个进程正在持有或 await 对其进行锁定,则同一可锁定对象可能会出现多次。但是,当前没有锁的对象将根本不会出现。

有几种不同类型的可锁定对象:整个关系(例如表),单个关系页面,单个关系 Tuples,事务 ID(虚拟 ID 和永久 ID)以及通用数据库对象(由 OID 类和 OID 对象标识,以与pg_descriptionpg_depend相同的方式)。同样,扩展关系的权利也表示为单独的可锁定对象。同样,可以对具有用户定义含义的数字进行“建议”锁定。

表 51.74. pg_locks

NameTypeReferencesDescription
locktypetext 可锁定对象的类型:relationextendpagetupletransactionidvirtualxidobjectuserlockadvisory
databaseoidpg_database.oid锁定目标所在的数据库的 OID;如果目标是共享库,则为零;如果目标是事务 ID,则为 null
relationoidpg_class.oid锁定目标的关系的 OID;如果目标不是关系或关系的一部分,则为 null
pageinteger 关系内锁所针对的页码;如果目标不是关系页或 Tuples,则为 null
tuplesmallint 页面内锁定所针对的 Tuples 号;如果目标不是 Tuples,则为 null
virtualxidtext 锁定目标的事务的虚拟 ID,如果目标不是虚拟事务 ID,则为 null
transactionidxid 锁所针对的 Transaction 的 ID;如果目标不是 TransactionID,则为 null
classidoidpg_class.oid包含锁定目标的系统目录的 OID;如果目标不是通用数据库对象,则为 null
objidoid任何 OID 列锁定目标的系统目录中的 OID;如果目标不是常规数据库对象,则为 null
objsubidsmallint 锁定目标的列号(classidobjid引用表本身);如果目标是其他通用数据库对象,则为零;如果目标不是通用数据库对象,则为 null
virtualtransactiontext 持有或 await 此锁的事务的虚拟 ID
pidinteger 持有或正在 await 此锁的服务器进程的进程 ID;如果该锁是由准备好的事务持有的,则为 null
modetext 此过程保持或需要的锁定模式的名称(请参见Section 13.3.1Section 13.2.3)
grantedboolean 如果持有锁,则为 true;如果 await 锁,则为 false
fastpathboolean 如果通过快速路径进行锁定,则为 true;如果通过主锁定表进行锁定,则为 false

granted在代表所指示进程持有的锁的行中为 true。 False 表示该进程当前正在 await 获取此锁,这意味着至少一个其他进程正在持有或 await 同一可锁定对象上的冲突锁定模式。await 过程将一直休眠,直到释放另一个锁(或检测到死锁情况)为止。一个进程可以 await 一次最多获取一个锁。

在整个事务运行过程中,服务器进程对事务的虚拟事务 ID 持有排他锁。如果将永久性 ID 分配给事务(通常仅在事务更改数据库状态时才会发生),它还会对事务的永久性事务 ID 持有排他锁,直到结束。当某个进程发现有必要专门 await 另一笔 Transaction 结束时,它会通过尝试获取另一笔 Transaction 的 ID(取决于情况的虚拟 ID 或永久 ID)上的共享锁来做到这一点。仅当另一个事务终止并释放其锁时,该操作才会成功。

尽管 Tuples 是对象的可锁定类型,但是有关行级锁的信息存储在磁盘上,而不是存储在内存中,因此行级锁通常不会出现在此视图中。如果进程正在 await 行级锁,则它通常在视图中显示为正在 await 该行锁的当前持有者的永久事务 ID。

可以在由单个bigint值或两个整数值组成的键上获取建议性锁定。将显示bigint键,其高阶部分在classid列中,其低阶部分在objid列中,并且objsubid等于 1.原始bigint值可以用表达式(classid::bigint << 32) | objid::bigint重新组合。显示整数键,第一个键在classid列中,第二个键在objid列中,并且objsubid等于 2.这些键的实际含义取决于用户。咨询锁对于每个数据库都是本地的,因此database列对于咨询锁很有意义。

pg_locks提供了数据库集群中所有锁的全局视图,而不仅仅是与当前数据库相关的那些锁。尽管其relation列可以与pg_class联接。 oid标识锁定的关系,这仅适用于当前数据库中的关系(那些database列是当前数据库的 OID 或零)。

pid列可以连接到pg_stat_activity视图的pid列,以获取有关持有或 await 每个锁的会话的更多信息,例如

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

另外,如果您使用的是预备事务,则可以将virtualtransaction列与pg_prepared_xacts视图的transaction列连接起来,以获取有关持有锁的预备事务的更多信息。 (一个准备好的事务永远不会 await 锁,但是它将 continue 保留在运行时获取的锁.)例如:

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

尽管可以通过将pg_locks与其自身联系来获取有关哪些进程阻止了其他进程的信息,但这很难在细节上做到正确。这样的查询将必须编码有关哪些锁定模式与其他锁定模式冲突的知识。更糟糕的是,pg_locks视图不会公开有关哪些进程在锁定 await 队列中领先于其他进程的信息,也不会公开有关哪些进程是代表其他哪些 Client 端会话运行的并行工作程序的信息。最好使用pg_blocking_pids()函数(请参阅Table 9.60)来确定 await 的进程被阻止在哪个进程之后。

pg_locks视图显示来自常规锁 Management 器和谓词锁 Management 器(它们是独立的系统)的数据;另外,常规锁 Management 器将其锁细分为常规锁和* fast-path *锁。不能保证此数据完全一致。查询视图时,一次从每个后端收集快速路径锁(带有fastpath = true)上的数据,而不会冻结整个锁 Management 器的状态,因此有可能在锁定时获取或释放锁信息收集。但是请注意,已知这些锁不会与当前存在的任何其他锁冲突。在查询了所有后端的快速路径锁之后,将常规锁 Management 器的其余部分作为一个单元锁定,并且将所有剩余锁的一致快照作为原子操作收集。解锁常规锁 Management 器后,谓词锁 Management 器也会类似地被锁定,并且所有谓词锁都作为原子动作收集。因此,除了快速路径锁之外,每个锁 Management 器都会提供一致的结果集,但是由于我们无法同时锁定两个锁 Management 器,因此在查询常规锁 Management 器之后可能会获取或释放锁。在询问谓词锁 Management 器之前。

如果非常频繁地访问该视图,则锁定常规和/或谓词锁定 Management 器可能会对数据库性能产生一些影响。这些锁仅保留从锁 Management 器获取数据所需的最短时间,但这并不能完全消除性能影响的可能性。