为什么db2频现“锁等待”或“911”错误
大家都知道,多个事务同时更新同一个数据行时必定要发生锁等待。虽然这个是造成锁等待或锁超时的原因,但不是全部。有不少同事在开发过程中发现这样的问题:自己只做一个根据主键update语句,就更新一行,且确知没有别人在更新这行,为什么语句迟迟没反应,想死锁了一样。本人通过几次尝试和试验发现了“秘密”。即db2的严重影响并发性能的地方:
1、无索引,relation scan 锁等待;
2、有索引,update时索引不能并发访问,需“串行”独占访问;
3、锁升级,行锁升级为表锁,阻塞其他事务的行级更新。
试验环境:
db2 v8系列或v9.1.4
db2命令行
主要步骤:
D:/>db2 create table t(id numeric not null,id2 numeric not null,name varchar(10),constraint t_p primary key(id,id2))
DB20000I SQL 命令成功完成。
D:/>db2 insert into t values(1,1,'chennan'),(1,2,'dba'),(1,3,'spsoft'),(2,1,'hubert'),(2,2,'nj_dba'),(2,3,'gdsy')
DB20000I SQL 命令成功完成。
D:/>db2 select * from t
ID ID2 NAME
------- ------- ----------
1. 1. chennan
1. 2. dba
1. 3. spsoft
2. 1. hubert
2. 2. nj_dba
2. 3. gdsy
6 条记录已选择。
开两个db2命令行窗口,模拟两个事务,考虑到最大并发性能,将这两个事务的隔离级别设为UR;且取消“自动提交”选项,以模拟长事务:
db2 => update command options using c off
DB20000I UPDATE COMMAND OPTIONS 命令成功完成。
db2 => set current isolation = ur
DB20000I SQL 命令成功完成。
================================================================
从前面表的定义,看出此表有主键,即在主键上有索引。下面看看这个索引对更新语句的影响:
事务一:
db2 => update t set name='eee' where id=1 and name='chennan'
DB20000I SQL 命令成功完成。
db2 =>
事务二:
db2 => update t set name='fff' where id=1 and name='spsoft'
现象是事务二的语句被阻塞,一直等待,如果数据库参数LOCKTIMEOUT=-1,只一直等待下去;如果是指定一个时间,则到时间会报“911”错误。
从更新内容上看,这两条语句更新不同的数据行,“应该”不会互相影响的,但事实上确实发生锁等待事件了。
开第三个db2命令行窗口,监视事务一、事务二的sql语句的执行路径相同:
Access Table Name = CWGLADM.T ID = 2,4
| Index Scan: Name = CWGLADM.T_P ID = 1
| | Regular Index (Not Clustered)
| | Index Columns:
| | | 1: ID (Ascending)
| | | 2: ID2 (Ascending)
| #Columns = 0
| #Key Columns = 1
| | Start Key: Inclusive Value
大家都知道,多个事务同时更新同一个数据行时必定要发生锁等待。虽然这个是造成锁等待或锁超时的原因,但不是全部。有不少同事在开发过程中发现这样的问题:自己只做一个根据主键update语句,就更新一行,且确知没有别人在更新这行,为什么语句迟迟没反应,想死锁了一样。本人通过几次尝试和试验发现了“秘密”。即db2的严重影响并发性能的地方:
1、无索引,relation scan 锁等待;
2、有索引,update时索引不能并发访问,需“串行”独占访问;
3、锁升级,行锁升级为表锁,阻塞其他事务的行级更新。
试验环境:
db2 v8系列或v9.1.4
db2命令行
主要步骤:
D:/>db2 create table t(id numeric not null,id2 numeric not null,name varchar(10),constraint t_p primary key(id,id2))
DB20000I SQL 命令成功完成。
D:/>db2 insert into t values(1,1,'chennan'),(1,2,'dba'),(1,3,'spsoft'),(2,1,'hubert'),(2,2,'nj_dba'),(2,3,'gdsy')
DB20000I SQL 命令成功完成。
D:/>db2 select * from t
ID ID2 NAME
------- ------- ----------
1. 1. chennan
1. 2. dba
1. 3. spsoft
2. 1. hubert
2. 2. nj_dba
2. 3. gdsy
6 条记录已选择。
开两个db2命令行窗口,模拟两个事务,考虑到最大并发性能,将这两个事务的隔离级别设为UR;且取消“自动提交”选项,以模拟长事务:
db2 => update command options using c off
DB20000I UPDATE COMMAND OPTIONS 命令成功完成。
db2 => set current isolation = ur
DB20000I SQL 命令成功完成。
================================================================
从前面表的定义,看出此表有主键,即在主键上有索引。下面看看这个索引对更新语句的影响:
事务一:
db2 => update t set name='eee' where id=1 and name='chennan'
DB20000I SQL 命令成功完成。
db2 =>
事务二:
db2 => update t set name='fff' where id=1 and name='spsoft'
现象是事务二的语句被阻塞,一直等待,如果数据库参数LOCKTIMEOUT=-1,只一直等待下去;如果是指定一个时间,则到时间会报“911”错误。
从更新内容上看,这两条语句更新不同的数据行,“应该”不会互相影响的,但事实上确实发生锁等待事件了。
开第三个db2命令行窗口,监视事务一、事务二的sql语句的执行路径相同:
Access Table Name = CWGLADM.T ID = 2,4
| Index Scan: Name = CWGLADM.T_P ID = 1
| | Regular Index (Not Clustered)
| | Index Columns:
| | | 1: ID (Ascending)
| | | 2: ID2 (Ascending)
| #Columns = 0
| #Key Columns = 1
| | Start Key: Inclusive Value