GaussDB(DWS)表级锁功能实操与思考

网友投稿 1425 2022-05-30

本人原来主要接触TD,表级锁的分类、场景等跟GaussDB(DWS)的锁类型有较大区别。TD的表级锁类型较少,GaussDB(DWS)的锁类型更细分一些。

此处对GaussDB(DWS)各种类型的锁都实操一下,加深学习。

锁类型

下图是各类型锁与互斥的关系

从锁的名称我们能大致将锁分为两类:SHARE锁、EXCLUSIVE锁。

这两类型锁的核心思想是,SHARE是多事务共享的,EXCLUSIVE是单事务独享的。根据不同场景分了一下8种锁类型。同时根据锁的相关性做了分类

ACCESS锁访问相关

ACCESS SHARE

SELECT命令在被引用的表上获得一个这种模式的锁,也就是说每当读取表的数据时,都会上一个ACCESS SHARE锁。只与ACCESS EXCLUSIVE锁冲突,也就是说除了DDL语句等,没有别的事务能阻止ACCESS SHARE锁下的读数据动作

ACCESS EXCLUSIVE

ACCESS EXCLUSIVE与所有锁类型冲突,这个模式保证其所有者(事务)是可以访问该表的唯一事务。

ALTER TABLE,DROP TABLE,TRUNCATE,REINDEX,CLUSTER,VACUUM FULL命令会自动请求这种锁。

在LOCK TABLE命令没有明确声明需要的锁模式时,它是缺省锁模式。

ACCESS SHARE与ACCESS EXCLUSIVE锁冲突例子:

--SESSION 1  begin; --对表locka加上ACCESS EXCLUSIVE锁 lock table  locka in access exclusive mode; --查询locka的数据 select * from locka;

--SESSION 2  begin; --对表locka加上ACCESS SHARE锁,此处会一直等待SESSION 1的ACCESS EXCLUSIVE锁,直到达到死锁超时。此处换成其他类型的锁结果都一样 lock table  locka in access share mode;

ROW行锁

ROW SHARE

SELECT FOR UPDATE和SELECT FOR SHARE命令会自动在目标表上请求ROW SHARE锁(且所有被引用但不是FOR SHARE/FOR UPDATE的其他表上,还会自动加上ACCESS SHARE锁)。

SELECT FOR UPDATE是对行加锁的语句,执行后指定行在其他事务中只能读;而其他行能够正常的增删改查。

表级加ROW SHARE锁后,行级也有锁的例子:

--SESSION 1  begin; --select for update语句自动会加上ROW SHARE select * from locka where col1 = 1 for update;

--SESSION 2  begin; --加上 row share lock lock table locka in row share mode; --查询session 1中指定行 select * from locka where col1 = 1; --查询其他行 select * from locka where col1 = 3; --执行对其他行的DML语句 delete locka where col1 = 3; --执行session 1中一样的行加锁语句,会等待session 1的事务结束,若执行对该行的增删改,也会发生冲突等待,因为该行已被sesion1加上了排他锁。 select * from locka where col1 = 1 for update;

增删改操作的锁

GaussDB(DWS)表级锁功能实操与思考

ROW EXCLUSIVE

UPDATE,DELETE,INSERT命令会自动在目标表上请求这个锁(且所有被引用的其他表上还会自动加上的ACCESS SHARE锁)。通常情况下,所有会修改表数据的命令都会请求表的ROW EXCLUSIVE锁。

SHARE UPDATE EXCLUSIVE

VACUUM(不带FULL选项),ANALYZE,CREATE INDEX CONCURRENTLY命令会自动请求这样的锁。

从锁冲突来看,不能够两个事务同时对同一个表进行VACUUM(不带FULL选项),ANALYZE等操作;一个表在进行DML操作时能够进行VACUUM和ANALYZE操作。下面两个例子展示ROW EXCLUSIVE与SHARE UPDATE EXCLUSIVE两种锁的使用

例子1,增删改时能操作VACUUM与ANALIZE:

--SESSION 1  begin; --插入操作 insert into locka values (8);

--SESSION 2 在session 1插入数据后 analyze locka; --vacuum vacuum locka; --查询当前locka的锁是否ROW EXCLUSIVE锁 select a.relname,b.mode from pg_class a inner join pg_locks b on a.oid = b.relation where relname = 'locka';

例子2,确认ANALYZE与VACUUM是SHARE UPDATE EXCLUSIVE锁;

--SESSION 1  begin; --给表上exclusive锁 lock table locka in exclusive mode;

--SESSION 2  --因为ANALYZE与VACUUM不能在显示事务中执行,下面就直接执行看,然后在另外的终端看后台的锁类型 analyze locka; vacuum locka;

--SESSION 3  --在另外的终端看后台的锁类型 select a.relname,b.mode from pg_class a inner join pg_locks b on a.oid = b.relation where relname = 'locka';

在查看vacuum的锁类型时,发现一个问题,就是vacuum显示的是只有AccessShareLock,并没有ShareUpdateExclusiveLock。同时如果只是ACCESSSHARE锁类型的话,那Exclusive锁是不会与之冲突,说明这里面有问题,不知道是pg_locks上显示的问题还是内部的问题了。

SHARE锁与EXCLUSIVE锁

SHARE

SHARE锁之间不冲突、SHARE锁对增删改的ROW EXCLUSIVE冲突。也就是说,两个事务持有SHARE锁,都不能再该事务内增删改,但是如果只有一个事务持有,那该事务是可以增删改的,因为锁冲突起码要有两个事务才行。

CREATE INDEX(不带CONCURRENTLY选项)语句会自动请求这种锁。

SHARE ROW EXCLUSIVE

此锁跟SHARE锁唯一区别是,与同样的锁会冲突,也就是说只能有一个事务能持有该锁,SHARE锁也不能加上。

任何SQL语句都不会自动请求这个锁模式。

EXCLUSIVE

EXCLUSIVE锁顾名思义就是独占了某个表,除了持有ACCESS SHARE锁的事务能访问该表。也就是说,只有对表的读动作可以和持有这个锁模式的事务并发执行。

任何SQL语句都不会在用户表上自动请求这个锁模式。然而在某些操作的时候,会在某些系统表上请求它。

例子:两事务加上SHARE锁后,不能对表增删改:

--SESSION 1  begin; --对表locka加上share锁 lock table lcoka in share mode; --等session 2上锁后,执行以下查询,预估执行成功 select * from locka;

--SESSION 2  begin; --对表locka加上share锁 lock table locka in share mode; --等session 1上锁后,执行以下查询,预估执行成功 select * from locka; --执行完session 1后,执行以下插入操作 insert into locka values (2);

--SESSION 3  --在另外的终端看后台的锁类型 select a.relname,b.mode from pg_class a inner join pg_locks b on a.oid = b.relation where relname = 'locka';

总结

各种SQL操作会自动加持的锁类型,如下表

VACUUM(不带FULL选项),ANALYZE命令会自动请求这样的锁。其中Vacuum在实验时从pg_locks的记录上不持有该类型锁,但表象是持有的。

我们重温一下上面锁冲突图片,并总结一般场景如下:

1、事务A在操作表结构,如ALTER TABLE,DROP TABLE,TRUNCATE,VACUUM FULL时,其他事务要操作该表只能等待该事务结束

2、事务A在建索引时(CREATE INDEX),其他事务没办法进行增删改操作;能两个事务同时给一个表进行建索引操作。

3、事务A在对表进行增删改操作时,能同时在另外的事务中进行VACUUM,ANALYZE操作,互不影响;但具体VACUUM与ANALYZE会因为增删改的改动导致执行结果不理想,因此我认为这两者还是不要并发执行。

4、虽然增删改的锁在表级锁层面不冲突,但操作某些行时,行上会有行级锁。例如事务A删除行1,事务B删除行1,两个事务结束前,必然有一方等待另一方结束。

5、事务A在查询表A,除非表A在进行DDL与VACUUM FULL等加持ACCESS EXCLUSIVE的锁,不然都能查询表A的数据。

与TD数据库锁的比较思考:

TD的表级锁只有4种,ACCESS、READ、WRITE、EXCLUSIVE。是不考虑并发对一个表进行增删改的。

这个我觉得是因为TD绝大部分都是AP的SQL,没有这样的TP场景,这样的4种锁能满足绝大部分的AP场景,所以TD的开发者在考虑锁的问题的时候就将表级锁简化为4种。

GaussDB(DWS)锁类型考虑了TP场景的,像增删改的RowExclusiveLock,是能够并发加持到同一个表的,而TD这4个锁是不能实现这个场景的,TD的增删改默认加的WRITE锁只能一个事务持有。当然了TD里面也有行级锁,但是使用的场景比较少。

总体来说TD的表级锁只适合AP场景,GaussDB(DWS)适合AP与TP场景。

以上是这两天对GaussDB(DWS)的锁的学习,希望能对读者有所帮助。

数据仓库服务 GaussDB(DWS) Gauss AP

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:一文了解NB- IoT四大关键特性以及实现技术
下一篇:FPGA从Xilinx的7系列学起(3)
相关文章