pg从9.3版本开始提供了lock_timeout参数用以指定锁超时时间,默认0,openGauss由于是基于9.2.4版本pg研发,所以没有这个参数,但是openGauss中存在两个参数控制着锁超时:lockwait_timeout,update_lockwait_timeout
对于这两个参数的解释如下:
lockwait_timeout:控制单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
update_lockwait_timeout:允许并发更新参数开启情况下,该参数控制并发更新同一行时单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
从字面意思和解释可以看到如果获取更新锁的时候走update_lockwait_timeout,如果不获取更新锁,那么走lockwait_timeout。
两个参数的默认值如下:
代码语言:javascript复制postgres=# show update_lockwait_timeout;
update_lockwait_timeout
-------------------------
2min
(1 row)
postgres=# show lockwait_timeout;
lockwait_timeout
------------------
20min
(1 row)
下面来验证一下这两个参数的区别,为了减少测试时间,我们将update_lockwait_timeout设置为10s,将lockwait_timeout设置为20s。该参数只能写入postgresql.conf配置文件中。
场景1:两个事物update同一行
会话1:
代码语言:javascript复制test=# begin;
BEGIN
test=# update test set id=2 where id=1;
UPDATE 1
会话2:
代码语言:javascript复制test=# timing
Timing is on.
test=# update test set id=3 where id=1;
ERROR: Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for ShareLock on transaction 102055465 after 10002.340 ms
DETAIL: blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode ExclusiveLock.
Time: 10017.495 ms
可以看到这个并发更新的锁走的是update_lockwait_timeout参数。
场景2:select for update场景
会话1:
代码语言:javascript复制test=# begin;
BEGIN
test=# update test set id=2 where id=1;
UPDATE 1
会话2:
代码语言:javascript复制test=# select * from test where id=1 for update;
ERROR: Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for ShareLock on transaction 102055467 after 10000.174 ms
DETAIL: blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode ExclusiveLock.
Time: 10006.634 ms
可以看到select for update依旧走的是更新锁update_lockwait_timeout锁超时参数。
场景3:显式lock table
会话1:
代码语言:javascript复制test=# begin;
BEGIN
test=# lock table test;
LOCK TABLE
会话2:
代码语言:javascript复制test=# update test set id=3 where id=1;
ERROR: Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for RowExclusiveLock on relation 16386 of database 16385 after 20002.091 ms
LINE 1: update test set id=3 where id=1;
^
DETAIL: blocked by hold lock thread 139785215145728, statement <lock table test;>, hold lockmode AccessExclusiveLock.
Time: 20008.300 ms
test=# select * from test;
ERROR: Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for AccessShareLock on relation 16386 of database 16385 after 20000.128 ms
LINE 1: select * from test;
^
DETAIL: blocked by hold lock thread 139785215145728, statement <lock table test;>, hold lockmode AccessExclusiveLock.
Time: 20006.237 ms
可以看到显式lock table时走的才是lockwait_timeout锁超时参数。
场景4:ddl
会话1:
代码语言:javascript复制test=# begin;
BEGIN
test=# update test set id=2 where id=1;
UPDATE 1
会话2:
代码语言:javascript复制test=# drop table test;
ERROR: Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for AccessExclusiveLock on relation 16386 of database 16385 after 20000.169 ms
DETAIL: blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode RowExclusiveLock.
Time: 20006.911 ms
test=# create index on test(id);
ERROR: Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for ShareLock on relation 16386 of database 16385 after 20000.102 ms
DETAIL: blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode RowExclusiveLock.
Time: 20006.578 ms
可以看到ddl等待锁的情况走的也是lockwait_timeout参数。
所以可以看到两个参数区别在于update_lockwait_tiemout在于控制并发更新同一行数据时的锁等待时间,而lockwait_timeout参数在于控制ddl锁等待以及显式lock table时的锁等待时间。