2024 年 9 月 26 日: PostgreSQL 17 发布!
支持版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不受支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

52.12. pg_locks #

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

pg_locks 针对每个活动的可锁定对象、请求的锁定模式和相关进程包含一行。 因此,如果多个进程正在持有或等待锁定某个可锁定对象,那么该可锁定对象可能会出现很多次。 但是,当前没有锁定其上的对象的任何锁的对象将完全不会出现。

有几种不同的可锁定对象类型:整个关系(例如,表)、关系的单个页、关系的单个元组、事务 ID (虚拟 ID 和永久 ID)、通用数据库对象(通过类 OID 和对象 OID 识别,与 pg_descriptionpg_depend 中相同)。此外,扩展关系的权利表示为一个单独的可锁定对象,更新 pg_database.datfrozenxid 的权利也是如此。此外,可以在具有用户定义意义的数字上获取 建议 锁定。

表 52.12. pg_locks

列 类型

描述

locktype text

可锁定对象的类型:relationextendfrozenidpagetupletransactionidvirtualxidspectokenobjectuserlockadvisoryapplytransaction。(另请参见 表 27.11。)

database oid(引用 pg_database.oid

锁定目标所在的数据库的 OID,如果目标是共享对象则为零,如果目标是事务 ID 则为 null

relation oid(引用 pg_class.oid

锁定目标的关系的 OID,如果目标不是关系或关系的一部分,则为 null

page int4

锁定目标在关系中的页号,如果目标不是关系页或元组,则为 null

tuple int2

锁定目标在页中的元组号,如果目标不是元组,则为 null

virtualxid text

锁定目标的事务的虚拟 ID,如果目标不是虚拟事务 ID,则为 null;请参见 第 66 章

transactionid xid

锁定目标的事务的 ID,如果目标不是事务 ID,则为 null;第 66 章

classid oid(引用 pg_class.oid

包含锁定目标的系统目录的 OID,如果目标不是通用数据库对象,则为 null

objid oid(引用任何 OID 列)

锁定目标在其系统目录中的 OID,如果目标不是通用数据库对象,则为 null

objsubid int2

锁定目标的列号(classidobjid 引用表本身),如果目标是其他通用数据库对象,则为零,如果目标不是通用数据库对象,则为 null

virtualtransaction text

持有或正在等待此锁的事务的虚拟 ID

pid int4

持有或正在等待此锁的服务器进程的进程 ID,如果锁定由准备好的事务持有,则为 null

mode text

此进程持有的或想要的锁定模式的名称(请参见 第 13.3.1 节第 13.2.3 节

granted bool

如果锁定已持有,则为真;如果锁定正在等待,则为假

fastpath bool

如果锁定是通过快速路径获取的,则为真;如果锁定是通过主锁定表获取的,则为假

waitstart timestamptz

服务器进程开始等待此锁的时间,如果锁定已持有,则为 null。请注意,即使 grantedfalse,在等待开始后的很短时间内,这也有可能为 null。


如果一行代表由指示的进程持有的锁定,则 granted 为真。假表示此进程当前正在等待获取此锁定,这意味着至少有一个其他进程正在持有或等待对相同可锁定对象的冲突锁定模式。等待进程将休眠,直到另一个锁定被释放(或检测到死锁情况)。单个进程一次最多只能等待获取一个锁定。

在整个事务运行过程中,服务器进程会对事务的虚拟事务 ID 持有排他锁定。如果事务分配了永久 ID (通常仅在事务更改数据库状态时才会发生),它也会对事务的永久事务 ID 持有排他锁定,直到事务结束。当进程发现有必要专门等待另一个事务结束时,它会通过尝试对另一个事务的 ID (根据情况,是虚拟 ID 或永久 ID)获取共享锁定来做到这一点。这只有在另一个事务终止并释放其锁定后才会成功。

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

推测性插入锁定包括事务 ID 和推测性插入标记。推测性插入标记显示在 objid 列中。

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

应用事务锁定在并行模式中用于应用逻辑复制中的事务。远程事务 ID 显示在 transactionid 列中。 objsubid 显示锁定子类型,该子类型对于用于同步一组更改的锁定为 0,对于用于等待事务完成以确保提交顺序的锁定为 1。

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

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

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

此外,如果您使用准备好的事务,则可以将 virtualtransaction 列与 pg_prepared_xacts 视图的 transaction 列连接,以获取有关持有锁定的准备好的事务的更多信息。(准备好的事务永远不会等待锁定,但它会继续持有它在运行时获取的锁定。)例如

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

虽然可以通过将 pg_locks 自身连接来获取有关哪些进程阻塞了哪些其他进程的信息,但要正确地做到这一点非常困难。这样的查询需要将有关哪些锁定模式与哪些其他锁定模式冲突的知识编码。更糟糕的是,pg_locks 视图没有公开有关哪些进程在锁定等待队列中领先于哪些其他进程的信息,也没有公开有关哪些进程是代表哪些其他客户端会话运行的并行工作进程的信息。最好使用 pg_blocking_pids() 函数(参见 表 9.69)来识别正在等待的进程被阻塞在哪些进程后面。

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

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

提交更正

如果您在文档中发现任何错误,与您对特定功能的体验不符或需要进一步澄清,请使用 此表单 报告文档问题。