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

54.12. pg_locks

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

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

有几种不同类型的可锁定对象: 整个关系(例如,表),关系的单个页面, 关系的单个元组, 事务ID(虚拟和永久ID均包括), 以及一般的数据库对象(由类OID和对象OID标识, 与pg_descriptionpg_depend中的方式相同)。 此外,扩展关系的权限被表示为一个单独的可锁定对象,以及更新 pg_databasedatfrozenxid的权限。 此外,可以对具有用户定义含义的数字进行咨询锁定。

表 54.12. pg_locks

列类型

描述

locktype text

可锁对象的类型: relation, extend, frozenid, page, tuple, transactionid, virtualxid, spectoken, object, userlock, or advisory. (参见 表 28.11.)

database oid (参考 pg_database.oid)

锁目标存在的数据库的OID,如果目标是一个共享对象则为0,如果目标是一个事务ID则为空

relation oid (参考 pg_class.oid)

作为锁目标的关系的OID,如果目标不是一个关系或者只是关系的一部分则此列为空

page int4

作为锁目标的页在关系中的页号,如果目标不是一个关系页或元组则此列为空

tuple int2

作为锁目标的元组在页中的元组号,如果目标不是一个元组则此列为空

virtualxid text

作为锁目标的事务虚拟ID,如果目标不是一个虚拟事务ID则此列为空

transactionid xid

作为锁目标的事务ID,如果目标不是一个事务ID则此列为空ID

classid oid (参考 pg_class.oid)

包含锁目标的系统目录的OID,如果目标不是一个普通数据库对象则此列为空

objid oid (参考 any OID column)

锁目标在它的系统目录中的OID,如果目标不是一个普通数据库对象则为空

objsubid int2

锁的目标列号(classidobjid指表本身),如果目标是某种其他普通数据库对象则此列为0,如果目标不是一个普通数据库对象则此列为空

virtualtransaction text

保持这个锁或者正在等待这个锁的事务的虚拟ID

pid int4

保持这个锁或者正在等待这个锁的服务器进程的PID,如果此锁被一个预备事务所持有则此列为空

mode text

此进程已持有或者希望持有的锁模式的名称(参见第 13.3.1 节第 13.2.3 节

granted bool

如果锁已授予则为真,如果锁被等待则为假

fastpath bool

如果锁通过快速路径获得则为真,通过主锁表获得则为假

waitstart timestamptz

当服务器进程启动的时候等待这个锁的时间,或在锁被持有的时候为空。 注意,在等待启动后,即使grantedfalse,这个也可以在很短的时间周期内为空。


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

在执行事务期间,服务器进程会对事务的虚拟事务ID持有独占锁。如果为事务分配了永久ID (通常仅在事务改变数据库状态时才会发生),它还会对事务的永久事务ID持有独占锁直到事务结束。 当一个进程发现有必要等待另一个事务结束时,它会尝试获取另一个事务ID(根据情况是虚拟ID还是永久ID) 的共享锁。只有当另一个事务终止并释放其锁时,这才会成功。

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

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

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.66)来识别等待进程被阻塞在哪个进程(es)之后。

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

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