Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

52.12. pg_locks #

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

pg_locks 为每个活动可锁定对象、请求的锁定模式和相关进程包含一行。因此,如果多个进程对同一个可锁定对象进行持有或等待锁,则该可锁定对象可能多次出现。但是,当前没有任何锁的可锁定对象根本不会出现。

有几种明显不同的可锁定对象类型:整个关系(例如,表)、关系的各个页面、关系的各个元组、事务 ID(虚拟 ID 和永久 ID)和通用数据库对象(由类 OID 和对象 OID 标识,与 pg_descriptionpg_depend 中的方式相同)。而且,扩展关系的权限作为一个单独的可锁定对象表示,同样还有更新 pg_database.datfrozenxid 的权限。此外,可以在具有用户定义含义的数字上获取 advisory 锁。

表 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 引用表本身),如果目标是其他常规数据库对象,则为 0,如果目标不是常规数据库对象,则为 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 为真。False 表明此进程当前正在等待获取此锁,这意味着至少还有其他一个进程正在持有或等待同一可锁定对象的冲突锁模式。等待进程将休眠,直到其他锁被释放(或检测到死锁情况)。单个进程一次最多只能等待获取一个锁。

在整个事务的运行期间,服务器进程对事务的虚拟事务 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)的数据,因此当搜集信息时,有可能进行锁确认或发布。不过请注意,已知这些锁不会与当前的任何其他锁冲突。在对所有后端进行快路径锁查询后,将锁定剩余的常规锁管理器作为单元,并且将所有剩余锁的一致快照作为原子操作进行收集。在解锁常规锁管理器后,以同样的方式锁定谓词锁管理器,并且将所有谓词锁作为原子操作进行搜集。因此,除了快路径锁之外,每个锁管理器将提供一组一致的结果,但由于我们没有同时锁定两个锁管理器,因此在查询常规锁管理器之后和查询谓词锁管理器之前,有可能确认或发布锁。

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