Postgresql 中文操作指南
54.12. pg_locks #
视图 _pg_locks_提供了访问数据库服务器中活动进程持有的锁的信息。参见 Chapter 13以了解关于锁定的更多讨论。
pg_locks 对每个活动可锁定对象、请求的锁定模式和相关的进程包含一行。因此,如果多个进程正在持有或等待对同一对象的锁定,则同一可锁定对象可能会出现多次。但是,如果某个对象当前没有任何锁定,则它将完全不会出现。
有几种不同类型的可锁对象:整个关系(例如,表)、关系的各个页面、关系的各个元组、事务 ID(虚拟 ID 和永久 ID)和通用数据库对象(通过类 OID 和对象 OID 标识,类似于 pg_description 或 pg_depend 中的标识方式)。此外,对关系进行扩展的权利表示为一个单独的可锁对象,就像更新 pg_database datfrozenxid 的权利一样。此外,还可以在具有用户定义意义的数字上获取“建议”锁。
Table 54.12. pg_locks Columns
Column Type Description |
locktype text 可锁对象的类型: relation 、 extend 、 frozenid 、 page 、 tuple 、 transactionid 、 virtualxid 、 spectoken 、 object 、 userlock 、 advisory 或 applytransaction 。(另请参见 Table 28.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;请参见 Chapter 74 |
transactionid xid 锁定目标的事务 ID,或在目标不是事务 ID 时为 null; Chapter 74 |
classid oid (引用 pg_class . oid )包含锁定目标的系统目录的 OID,如果目标不是通用数据库对象,则为 null |
objid oid (引用任意 OID 列)锁定目标在其系统目录中的 OID,如果目标不是通用数据库对象,则为 null |
objsubid int2 锁定的列号( classid 和 objid 指表本身),如果目标是其他通用数据库对象,则为 0,如果目标不是通用数据库对象,则为 null |
virtualtransaction text 持有或等待此锁定的事务的虚拟 ID |
pid int4 持有或等待此锁定的服务器进程的进程 ID,如果锁由预先准备的事务持有,则为 null |
mode text 此进程所持有的或所期望的锁定模式的名称(参见 Section 13.3.1 和 Section 13.2.3 ) |
granted bool 如果锁定被持有则为真,如果锁定被等待则为假 |
fastpath bool 如果锁定通过快速路径获取则为真,如果通过主锁定表获取则为假 |
waitstart timestamptz 服务器进程开始等待此锁定的时间,如果锁定被持有则为 null。请注意,即使 granted 为 false ,但在等待开始之后的极短时间内,该值也可能为 null。 |
granted 在表示由指定进程持有的锁定的行中为 true。False 表示此进程当前正等待获取此锁定,这意味着至少还有另一个进程在持有或等待对相同可锁定对象的冲突锁定模式。等待进程将休眠,直到其他锁定释放(或检测到死锁情况)。单个进程最多可以一次等待获取一个锁定。
在运行事务期间,服务器进程对事务的虚拟事务 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 或 0 的关系)。
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() 函数(参见 Table 9.67)来识别等待进程被哪个进程阻塞。
pg_locks 视图显示来自常规锁定管理器和谓词锁定管理器的数据,它们是分离的系统;此外,常规锁定管理器将其锁定细分为常规锁定和 fast-path 锁定。不能保证此数据完全一致。在查询视图时,从每个后端一次收集快速路径锁定(其中 fastpath = true)上的数据,而不冻结整个锁定管理器的状态,因此有可能会在收集信息时获取或释放锁定。但是,请注意,这些锁定已知不会与当前存在的任何其他锁定冲突。在查询所有后端以查找快速路径锁定后,常规锁定管理器剩余部分将作为一个单元进行锁定,然后以原子操作的方式收集所有剩余锁定的快照。在解锁常规锁定管理器后,将以类似方式锁定谓词锁定管理器,并以原子操作的方式收集所有谓词锁定。因此,除了快速路径锁定之外,每个锁定管理器都会提供一组一致的结果,但是由于我们没有同时锁定两个锁定管理器,所以有可能在我们询问常规锁定管理器并在我们询问谓词锁定管理器之前,锁定已被获取或释放。
如果此视图非常频繁地访问,则锁定常规锁定管理器和/或谓词锁定管理器可能会对数据库性能产生一些影响。这些锁定只保持获取锁定管理器数据所需的最小时间,但这并不能完全消除性能影响的可能性。