PostgreSQL 之 锁的查看

 作者:瀚高PG实验室 (Highgo PG Lab)- 天蝎座

要查看pg中的锁,需要查看pg_locks这个视图

pg_locks 字段

名称

类型

引用

描述

locktype

text

 

可锁对象的类型: relation, extend, page, tuple, transactionid, virtualxid, object, userlock, or advisory

database

oid

g_database.oid

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

relatio

oid

g_class.oid

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

age

integer

 

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

tuple

mallint

 

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

virtualxid

text

 

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

transactionid

xid

 

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

classid

oid

g_class.oid

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

objid

oid

任意OID列

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

objsubid

mallint

 

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

virtualtransaction

text

 

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

id

integer

 

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

mode

text

 

此进程已持有或者希望持有的锁模式(参见Section 13.3.1和Section 13.2.3)

granted

oolea

 

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

fastpath

oolea

 

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

virtualxid:虚拟事务id,每次生成一个事务,会在pg_clog下的commit log 文件中占用2bit空间,因为有些事务中没有实际的操作数据的语句,所以这种分配事务id有些浪费空间了,于是提出了虚拟事务的概念,主要是为了节省空间。在mysql中针对只读事务是有优化的,只读事务是没有分配事务id的。

下面开2个session看下锁的情况

Session A:

select pg_backend_pid();

20353

创建表并lock

create table t(id integer);
insert into t values(1);


begin;
lock table t;

Session B:

select * from pg_locks where pid=20353;

或者

Select locktype,relation::regclass as rel,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted

From pg_locks

Where pid=20353;  

 

看到xid是空的,没有实际事务,granted是t,表示持有锁.

session B 

也试图lock表看下情况

testdb=# select pg_backend_pid();

 pg_backend_pid

----------------

          20171

(1 row)

begin;
lock table t;

一直提示查询运行中,被阻塞了!

Session A

查看下锁的信息

select * from pg_locks where pid=20171;

或者

Select locktype,relation::regclass as rel,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted

From pg_locks

Where pid=20171;   

#这个sql 语句中字段relation::regclass,作用是可以直接获取到被锁定对象的名称!

看到20171,也就是session b的granted是f,也就是在发起请求获得锁,同时对于session B也有virtualxid的exclusiveLock锁,就是对于事务id加了锁。

Session A提交后,session B就获得了锁。

 

    

session A中对行操作,看下行锁是什么样的情况

A:

begin;
update t set id=5;

看到事务中有了行排他锁出现,并且出现了transactionid并且xid是1860的行,说明这个是有实际数据操作的事务

testdb=# select locktype,relation::regclass as rel,page||','||tuple as ctid,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted from pg_locks where pid=20353;

 

session B中也更新下行,看下情况
begin;
update t set id=10;

出现了阻塞,看下视图的情况

启动Session C查看锁

testdb=# select locktype,relation::regclass as rel,page||','||tuple as ctid,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted from pg_locks where pid in (20171,20353);

 

如果想看哪个进程被阻塞了,只需要看“granted”字段值为“f”的pid即可。

加行锁的过程,是首先在表上加一个表级意向锁’。

pg_locks并不能显示出每个行锁的信息,原因很简单,行锁信息并不会记录到共享内存中,如果每个行锁在内存中存在一条记录的话,在对表做全表更新时,表有多少行,就需要在内存中记录多少条行锁信息,内存会容易吃不消。

行锁的阻塞信息是通过“transactionid”类型的锁体现出来的。从原理上来说,行锁是会在数据行上加上自己的xid的,另一个进程读到这一行时,如果发现有行锁,会把行上另一个事务的xid读出来,然后申请在这个xid上加“share”锁。而持有行锁的进程已经在此xid上加了“Exclusive”的锁,所以后边要更新这行的进程会被阻塞。

如上边截图中进程20171获取“share”被xid为1860的事务阻塞,xid 1860 对应进程20353 已经获得 “Exclusive”

select locktype,relation::regclass as rel,page||','||tuple as ctid,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted from pg_locks;

 

select * from t where ctid='(0,1)';

 

看到是t表中id=1的记录导致阻塞

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值