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

举报
SeqList 发表于 2020/08/06 11:04:12 2020/08/06
【摘要】 本文主要对GaussDB(DWS)里面的锁类型进行了解读与实操,并总结一般我们的使用场景系统会自动加些什么锁,哪些SQL因为锁的原因不能一起执行等


本人原来主要接触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;


增删改操作的锁

  • 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操作会自动加持的锁类型,如下表

锁类型 SQL操作
AccessShareLock SELECT等访问表数据相关语句,如insert select等语句也会对源头表加持该锁
RowShareLock SELECT FOR UPDATE、SELECT FOR SHARE等加持行级锁时,对该表加的锁
RowExclusiveLock 增删改(INSERT、DELETE、UPDATE)时自动对目标表加持的锁类型
ShareUpdateExclusiveLock

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

ShareLock CREATE INDEX语句会自动请求这种锁。
ShareRowExclusiveLock 任何SQL语句都不会自动请求这个锁模式
ExclusiveLock 任何SQL语句都不会自动请求这个锁模式
AccessExclusiveLock ALTER TABLE,DROP TABLE,TRUNCATE,REINDEX,CLUSTER,VACUUM FULL命令会自动请求这种锁



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

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)的锁的学习,希望能对读者有所帮助。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。