DB2数据库发生死锁了怎么办
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DB2数据库发生死锁了怎么办相关的知识,希望对你有一定的参考价值。
db2 get snapshot for locks on sampledb2 get db cfg for sample
db2 update db cfg using dlchktime 10000
-查看数据库管理器级别快照信息
db2 get snapshot for dbm
-查看数据库级别快照信息
db2 get snapshot for database on dbname
-查看应用级别快照信息
db2 get snapshot for application agentid appl-handler
注:appl-handler可以从list applicaitions的输出中得到
-查看表级别快照信息
db2 get snapshot for tables on dbname
注:需要把tables快照开关设为ON才会有作用
-查看锁快照信息
db2 get snapshot for locks on dbname
或
db2 get snapshot for locks on for application agentid appl-handler
-查看动态sql语句快照信息
db2 get snapshot for dynamic sql on dbname
db2 get monitor switches
db2 update monitor switches using lock on statement on
create event monitor mymonitor for deadlocks,statements write to file \'c:/temp\'
set event monitor mymonitor state 1
db2evmon - path \'c:/temp\'
--转自:http://blog.csdn.NET/rodjohnsondoctor/article/details/4323514
---
第1页:上线前的准备
第2页:维护时的注意事项
第3页:发生死锁后的对策
【IT168 技术文档】在新的数据库应用系统上线初期,由于测试不完善或不熟悉DB2的机制,常会出现锁等待死锁等现象存在于我们的应用系统中,如何捕获锁等待或死锁信息并解决锁问题,是保证平稳上线必须面对的问题。目前应用系统最常使用的DB2数据库版本有多个,有8.1,8.2,9.1还有新推出的9.5,对于不同版本的DB2数据库提供的解决办法不尽相同,下面对于上述问题的解决作了一个简单说明,希望对大家有用。
首先在上线前有几件跟锁相关的事情需要开发设计人员一定要做好
1. 相关参数的更改
注册表变量参数:
DB2_EVALUNCOMMITTED=on 当启用此变量时,在可能的情况下,它将进行表或索引访问扫描以延迟或避免行锁定,直到知道数据记录满足谓词求值为止。
DB2_SKIPDELETED=on 当启用此变量时,在可能的情况下,它允许使用无条件地跳过已删除的键或跳过已删除的行。
DB2_SKIPINSERTED=on 当启用此变量时,在可能的情况下,它允许跳过未落实的已插入行,就好像从未插入这些行一样。
数据库参数:
LOCKLIST 锁定列表的内存量,当此参数设置为 AUTOMATIC 时,就启用了自调整功能。这允许内存调整器根据工作负载需求变化动态地调整此参数控制的内存区大小。如果不是自动,需要设置相对大一些;DB2默认是行锁,每个行锁大约占64或128个字节(64位数据库),计算锁定列表内存的大小公式是: ( 每个应用程序的平均锁定数目的估计值 * 每个锁定所需的字节数(128或64) * maxappls(或者max_coordagents) /4096 ) * 120%,这里只是建议公式,实际情况还要视操作系统实际的内存量来定。
MAXLOCKS 升级前锁定列表的最大百分比,默认是22%(windows)或10%(unix),可以根据要求自行改动,计算公式是 2 * 100 / maxappls
DLCHKTIME 死锁检测时间间隔,默认是10000毫秒(10秒),可以根据要求自行改动,也可不动。增大此参数以降低检查死锁的频率,因此增加应用程序必须等待消除死锁的时间。 减小此参数会增大检查死锁的频率,从而减少应用程序必须等待死锁解决的时间,但是会增加数据库管理器检查死锁所花的时间。
LOCKTIMEOUT 锁等待时间,默认是 -1,也就是永远等待,请改成固定的值,在事务处理(OLTP)环境中,可以使用 30 秒的初始启动值。在一个只查询的环境中,您可以从一个较高的值开始。
LOGFILSIZ 日志文件大小,此参数定义每个主日志文件和辅助日志文件的大小。如果数据库要运行大量更新、删除或插入事务,而这将导致日志文件很快变满,则应增大日志文件,了解您的并发应用程序的日志记录需求,来确定一个不会分配过量而浪费空间的日志文件大小。
LOGPRIMARY 主日志文件数,了解您的并发应用程序的日志记录需求,适当增大日志文件数。
注意: 在更新参数时,需要注意有些参数在更改后需要重新启动数据库DB2实例才可以生效;有些参数需要断开当前所有的应用程序,重新链接才能生效;有些参数可以立即生效,使用者请参考相关文档,注意参数生效特性。
2. 应用程序设计
-程序尽量短小精悍
-程序尽量晚地访问关键资源
-程序尽可能快地提交工作
-程序尽可能快地关闭游标
-建立合适索引
3. 性能测试
要根据将来实际的并发用户数和数据量进行测试
上线之后维护时我们要做的几件事情
1. 做好定期维护
通过使用如下命令进行维护:
-reorg表和索引定期重组
-runstats表和索引的统计信息定期更新
-rebind 程序包定期重新编译 参考技术A 重启数据库。
[译文]MySQL发生死锁肿么办?
原文出处:https://www.percona.com/blog/2014/10/28/how-to-deal-with-mysql-deadlocks/
译者:何金龙,知数堂同学,前阿里人,爱好和支持开源技术,代码洁癖、简单主义者,擅长 PHP,ruby on rails 和 Python 编程,现在供职于要出发,担任 MySQL DBA。
备注:老叶对本译文其中一小部分做了修订。
在 MySQL 中,当两个或以上的事务相互持有和请求锁,并形成一个循环的依赖关系,就会产生死锁。在一个事务系统中,死锁是确切存在并且是不能完全避免的。 InnoDB 会自动检测事务死锁,立即回滚其中某个事务,并且返回一个错误。它根据某种机制来选择那个最简单(代价最小)的事务来进行回滚。偶然发生的死锁不必担心,但死锁频繁出现的时候就要引起注意了。
在 MySQL 5.6 之前,只有最新的死锁信息可以使用 show engine innodb status 命令来进行查看。使用 Percona Toolkit 工具包中的 pt-deadlock-logger 可以从 show engine innodb status 的结果中得到指定的时间范围内的死锁信息,同时写入文件或者表中,等待后面的诊断分析。对于 pt-deadlock-logger 工具的更多信息可以参考手册:https://www.percona.com/doc/percona-toolkit/2.2/pt-deadlock-logger.html 。 如果使用的是 MySQL 5.6 或以上版本,您可以启用一个新增的参数 innodb_print_all_deadlocks 把 InnoDB 中发生的所有死锁信息都记录在错误日志里面。
在开始讲诊断之前,得到应用程序捕捉到的死锁错误(MySQL error no. 1213),以及通过重试来处理失败事务是一个重要的做法。
如何诊断MySQL 死锁
一个 MySQL 死锁可能会涉及到两个或以上的事务,而 LATEST DETECTED DEADLOCK 这一节仅仅展示了最后两个事务,并且只显示这两个事务中最后执行的一条语句和循环依赖中的锁信息。而忽略掉了前面执行过的有可能真正申请并持有锁的语句。下面我会给大家讲一些如何收集这些被忽略掉的语句的 tips。
让我们一起来看两个例子,看 LATEST DETECTED DEADLOCK 都给出了什么信息。例 1:
1 141013 6:06:22 2 *** (1) TRANSACTION: 3 TRANSACTION 876726B90, ACTIVE 7 sec setting auto-inc lock 4 mysql tables in use 1, locked 1 5 LOCK WAIT 9 lock struct(s), heap size 1248, 4 row lock(s), undo log entries 4 6 MySQL thread id 155118366, OS thread handle 0x7f59e638a700, query id 87987781416 localhost msandbox update 7 INSERT INTO t1 (col1, col2, col3, col4) values (10, 20, 30, 'hello') 8 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: 9 TABLE LOCK table `mydb`.`t1` trx id 876726B90 lock mode AUTO-INC waiting 10 *** (2) TRANSACTION: 11 TRANSACTION 876725B2D, ACTIVE 9 sec inserting 12 mysql tables in use 1, locked 1 13 876 lock struct(s), heap size 80312, 1022 row lock(s), undo log entries 1002 14 MySQL thread id 155097580, OS thread handle 0x7f585be79700, query id 87987761732 localhost msandbox update 15 INSERT INTO t1 (col1, col2, col3, col4) values (7, 86, 62, "a lot of things"), (7, 76, 62, "many more") 16 *** (2) HOLDS THE LOCK(S): 17 TABLE LOCK table `mydb`.`t1` trx id 876725B2D lock mode AUTO-INC 18 *** (2) WAITING FOR THIS LOCK TO BE GRANTED: 19 RECORD LOCKS space id 44917 page no 529635 n bits 112 index `PRIMARY` of table `mydb`.`t2` trx id 876725B2D lock mode S locks rec but not gap waiting 20 *** WE ROLL BACK TRANSACTION (1) |
第 1 行是死锁发生的时间。如果你的应用程序捕捉和记录死锁错误到日志中,那么你可以根据这个时间戳和应用程序日志中的死锁错误的时间戳进行匹配。这样你可以得到已回滚的事务,及事务中的所有语句。
第 3 和 11 行,注意事务的序号和活跃时间。如果你定期地把 show engine innodb status 的输出信息记录到日志文件(这是一个很好的做法),那么你就可以使用事务编号在之前的输出日志中查到同一个事务中所希望看到的更多的语句。活跃时间提供了一个线索来判断这个事务是单个语句的事务,还是包含多个语句的事务。
第 4 和 12 行,使用到的表和锁只是针对于当前的语句。因此,使用到一张表,并不意味着事务仅仅涉及到一张表。
第 5 和 13 行,这里的信息需要重点关注,因为它告诉我们事务做了多少的改变,也就是 "undo log entries";"row lock(s)" 则告诉我们持有多少行锁。这些信息都会提示我们这个事务的复杂程度。
第 6 和 14 行,留意线程 ID、连接主机和用户。如果你在不同的应用程序中使用不同的 MySQL 用户,这将是另外一个好的习惯,这样你就可以根据连接主机和用户来定位到事务来自于哪个应用程序。
第 9 行,对于第一个事务,它只是显示了处于锁等待状态,在这个例子中,是表 t1 的 AUTO_INC 锁。其他的可能:共享锁(S),有间隙锁(gap lock)的排他锁(X),及没有间隙锁(gap lock)的排他锁(X)。
第 16 和 17 行,对于第二个事务,显示了它持有的锁,在本示例中,是事务1 (TRANSACTION (1)) 所请求并等待中的 AUTO-INC 锁。
第 18 和 19 行,显示了事务2 (TRANSACTION (2)) 所等待的锁的信息。在本例中,是一个在另一个表 t2 的主键上面共享的没有间隙的记录锁。在 InnoDB 中只有少数情况会产生 共享记录锁:
1) 使用了 SELECT … LOCK IN SHARE MODE 的语句
2) 外键引用记录
3) 源表上的共享锁,使用了 INSERT INTO… SELECT 的语句
事务2 的当前语句是一个简单的 insert to t1,所以 1 和 3 被排除了。通过检查 show create table t1,你可以确定共享锁(S) 是由于父表t2 的外键一致性约束。
例 2:使用 MySQL 社区版,每个记录锁的记录内容都会被打印出来。
1 2014-10-11 10:41:12 7f6f912d7700 2 *** (1) TRANSACTION: 3 TRANSACTION 2164000, ACTIVE 27 sec starting index read 4 mysql tables in use 1, locked 1 5 LOCK WAIT 3 lock struct(s), heap size 360, 2 row lock(s), undo log entries 1 6 MySQL thread id 9, OS thread handle 0x7f6f91296700, query id 87 localhost ro ot updating 7 update t1 set name = 'b' where id = 3 8 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: 9 RECORD LOCKS space id 1704 page no 3 n bits 72 index `PRIMARY` of table `tes t`.`t1` trx id 2164000 lock_mode X locks rec but not gap waiting 10 Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bit s 0 11 0: len 4; hex 80000003; asc ;; 12 1: len 6; hex 000000210521; asc ! !;; 13 2: len 7; hex 180000122117cb; asc ! ;; 14 3: len 4; hex 80000008; asc ;; 15 4: len 1; hex 63; asc c;; 16 17 *** (2) TRANSACTION: 18 TRANSACTION 2164001, ACTIVE 18 sec starting index read 19 mysql tables in use 1, locked 1 20 3 lock struct(s), heap size 360, 2 row lock(s), undo log entries 1 21 MySQL thread id 10, OS thread handle 0x7f6f912d7700, query id 88 localhost r oot updating 22 update t1 set name = 'c' where id = 2 23 *** (2) HOLDS THE LOCK(S): 24 RECORD LOCKS space id 1704 page no 3 n bits 72 index `PRIMARY` of table `tes t`.`t1` trx id 2164001 lock_mode X locks rec but not gap 25 Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bit s 0 26 0: len 4; hex 80000003; asc ;; 27 1: len 6; hex 000000210521; asc ! !;; 28 2: len 7; hex 180000122117cb; asc ! ;; 29 3: len 4; hex 80000008; asc ;; 30 4: len 1; hex 63; asc c;; 31 32 *** (2) WAITING FOR THIS LOCK TO BE GRANTED: 33 RECORD LOCKS space id 1704 page no 3 n bits 72 index `PRIMARY` of table `tes t`.`t1` trx id 2164001 lock_mode X locks rec but not gap waiting 34 Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bit s 0 35 0: len 4; hex 80000002; asc ;; 36 1: len 6; hex 000000210520; asc ! ;; 37 2: len 7; hex 17000001c510f5; asc ;; 38 3: len 4; hex 80000009; asc ;; 39 4: len 1; hex 62; asc b;; |
第 9 和 10 行:"space id" 是表空间 ID,"page no" 指出了这个表空间里面记录锁所在的数据页,"n bits" 不是数据页偏移量,而是锁位图里面的 bits 数。在第 10 行记录的 "heap no" 是数据页偏移量。
第 11 到 15 行:显示了记录数据的十六进制编码。字段 0 表示聚集索引(即主键),忽略最高位,值为 3。字段 1 表示最后修改这条记录的事务的ID号,上面实例中的十进制值是 2164001,即是 TRANSACTION (2)。字段 2 表示回滚指针。从字段 3 开始,表示的是余下的行数据:字段 3 表示一个整型列,值为 8,字段 4 表示一个字符串列,值为 'c'。通过阅读这些信息,我们可以准确知道哪一行被锁了,哪些是当前值。
我们还可以从分析中学到什么?
既然大多数 MySQL 死锁是发生在两个事务之间,那么我们可以基于这个假设来进行分析。在例1 中,事务2 (trx(2)) 在等待一个共享锁,因此事务1 (trx(1)) 在表 t2 的主键记录上,要么持有一个共享锁,要么持有一个排他锁。假设 col2 是一个外键列,通过检查 trx(1) 的当前语句,我们可以知道它不需要相同的记录锁,因而它肯定是一些在 trx(1) 之前就已经申请了在 t2 主键索引上的 S 或者 X 锁的语句。trx(1) 在 7 秒钟里面仅改变了 4 行数据。
因此,我们可以得到 trx(1) 的一些特征:它做了很多处理,却做了很少变化;变化涉及到 t1 和 t2,单个记录插入到 t2。这些信息结合着其他数据可以帮助开发人员定位到那个事务。
我们还可以从哪里找到事务之前的语句?
除了应用程序日志和之前的 show engine innodb status 的输出信息外,还可以利用 binlog、low log,甚至是 general log。
通过 binlog,如果 binlog_format = statement,binlog 中的每个 event 都会拥有一个 thread_id。只有已提交的事务会被记录到 binlog 中,因此,我们只能在 binlog 中查找 trx(2) 的细信息。在例1 中,我们知道死锁发生的时间,还有 trx(2) 是在 9 秒前开始的。我们可以执行 mysqlbinlog 命令来解析对应的 binlog 文件,并且寻找带有 thread_id = 155097580 的语句。使用应用程序代码来进行交叉确认也是很好的。
$ mysqlbinlog -vvv --start-datetime=“2014-10-13 6:06:12” --stop-datatime=“2014-10-13 6:06:22” mysql-bin.000010 > binlog_1013_0606.out |
在 Percona Server 5.5 或者更早版本,可以通过设置 log_slow_verbosity 选项来把 事务 ID 记录在 slow log 中。如果你设置了 long_query_time = 0,你可以捕获到包括那些回滚到 slow log 里面的所有语句。通过 general log,可以用 thread id 来查找相关的语句。
如何避免死锁。
在了解死锁之后,我们可以做一些事情来避免它。
对应用程序进行调整/修改。在某些情况下,你可以通过把大事务分解成多个小事务,使得锁能够更快被释放,从而极大程度地降低死锁发生的频率。在其他情况下,死锁的发生是因为两个事务采用不同的顺序操作了一个或多个表的相同的数据集。需要改成以相同顺序读写这些数据集,换言之,就是对这些数据集的访问采用串行化方式。这样在并发事务时,就让死锁变成了锁等待。
修改表的 schema,例如删除外键约束来分离两张表,或者添加索引来减少扫描和锁定的行。
如果发生了间隙锁,你可以把会话或者事务的事务隔离级别更改为 RC(read committed)级别来避免,但此时需要把 binlog_format 设置成 row 或者 mixed 格式。
以上是关于DB2数据库发生死锁了怎么办的主要内容,如果未能解决你的问题,请参考以下文章