支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 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

如果持有锁则为 true,如果正在等待锁则为 false

fastpath bool

如果锁是通过快速路径获取的,则为 true,如果锁是通过主锁表获取的,则为 false

waitstart timestamptz

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


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

在运行事务的整个过程中,服务器进程对事务的虚拟事务 ID 持有独占锁。如果将永久 ID 分配给事务(通常只有在事务更改数据库状态时才会发生这种情况),它还对事务的永久事务 ID 持有独占锁,直到事务结束。当进程发现有必要专门等待另一个事务结束时,它会尝试获取对另一个事务 ID 的共享锁(虚拟 ID 或永久 ID,具体取决于情况)。只有在另一个事务终止并释放其锁时,才会成功。

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

推测插入锁由事务 ID 和推测插入令牌组成。 推测插入令牌显示在 objid 列中。

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

应用事务锁在并行模式下用于在逻辑复制中应用事务。transactionid 列中显示远程事务 ID。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),而不会冻结整个锁管理器的状态,因此在收集信息时可能会获取或释放锁。但请注意,已知这些锁与当前存在的任何其他锁都不冲突。在查询所有后端的快速路径锁之后,其余的常规锁管理器作为一个单元被锁定,并且以原子操作的方式收集所有剩余锁的一致快照。在解锁常规锁管理器后,谓词锁管理器也会以类似的方式锁定,并以原子操作的方式收集所有谓词锁。因此,除了快速路径锁之外,每个锁管理器都将提供一组一致的结果,但是由于我们不同时锁定两个锁管理器,因此可能在查询常规锁管理器之后和查询谓词锁管理器之前获取或释放锁。

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

提交更正

如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。