PostgreSQL 之 锁的查看

要查看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的。

 

下面开2session看下锁的情况

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;  

 PostgreSQL 之 锁的查看_第1张图片

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

 

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,作用是可以直接获取到被锁定对象的名称!

PostgreSQL 之 锁的查看_第2张图片

看到20171,也就是session bgrantedf,也就是在发起请求获得锁,同时对于session B也有virtualxidexclusiveLock锁,就是对于事务id加了锁

 

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

 PostgreSQL 之 锁的查看_第3张图片

    

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

A:

begin;
update t set id=5;

 

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

 

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;

 PostgreSQL 之 锁的查看_第4张图片


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);

 PostgreSQL 之 锁的查看_第5张图片

 

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

 

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

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

 

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

 

如上边截图中进程20171获取“share”被xid1860事务阻塞,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;

 PostgreSQL 之 锁的查看_第6张图片

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

 PostgreSQL 之 锁的查看_第7张图片

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


你可能感兴趣的:(Highgo,DB,PostgreSQL)