Chinaunix首页 | 论坛 | 博客
  • 博客访问: 105655233
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655234
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655235
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655236
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655237
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655238
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655229
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655240
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655241
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655242
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655243
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655244
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655245
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655246
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655247
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655248
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655249
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655250
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655252
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655253
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655244
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655255
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655256
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655257
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655258
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655259
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655260
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655261
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655262
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655263
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655264
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655265
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655266
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655267
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655268
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655259
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655270
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655271
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655272
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655273
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655274
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655275
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655276
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655277
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655278
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655279
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655280
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655281
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655282
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655283
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655274
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks

DB2 9 基础(730 考试)认证指南,第 6 部分: 数据并发性(5)-sdccf-ChinaUnix博客
  • 博客访问: 105655285
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 19:20:13

developerWorks



锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107721) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107720) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107719) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107718) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107717) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107716) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107715) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107714) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107713) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107712) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107711) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107710) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107709) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107708) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107707) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107706) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107705) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107704) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107703) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107702) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107701) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107700) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107699) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107698) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107697) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107696) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107695) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107694) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107693) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107692) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107691) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107690) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107689) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107688) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107687) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107686) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107685) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107684) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107683) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107682) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107681) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107680) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107679) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107678) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107677) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107676) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107675) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107674) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107673) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107672) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107671) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


锁和性能

如果数据资源上的一种锁状态允许在同一资源上放置另一个锁,就认为这两种锁(或两种状态)是兼容的。每当一个事务持有数据资源上的锁,而第二个事务请求同一资源上的锁时,DB2 数据库管理程序会检查两种锁状态以判断它们是否兼容。如果锁是兼容的,则将锁授予第二个事务(假定没有其他事务在等待该数据资源)。但是,如果锁不兼容,则第二个事务必须等待,直到第一个事务释放它的锁为止,然后它才可以获取对资源的访问权并继续处理。(如果资源上有多个与新请求的锁不兼容的锁,则第二个事务必须等到它们全部被释放为止。)请参阅 IBM DB2 9 Administration Guide: Performance 文档(或在 DB2 信息中心搜索 Lock type compatibility 主题)以获取关于各个锁之间是否兼容的特定信息。

当事务尝试访问它已经持有锁的数据资源,但是所需的访问模式需要比已持有的锁更严格的锁时,则所持有的锁的状态更改成更严格的状态。将已经持有的锁的状态更改成更严格状态的操作称为锁转换。发生锁转换是因为一个事务同一时间内只能在一个数据资源上持有一个锁。

在大多数情况下,对行级锁执行锁转换,转换过程相当简单。例如,如果持有共享(S)或更新(U)行级锁,但是需要互斥(X)锁,则所持有的锁将被转换成互斥(X)锁。但意向互斥(IX)锁和共享(S)锁是特例,因为无法确定其中哪个更严格。因此,如果持有其中一种行级锁但又需要另一种锁,则所持有的锁将转换成带意向互斥的共享(SIX)锁。假定所请求的锁状态更严格的话,则类似的转换会使所请求的锁状态成为持有锁的新状态。(仅当所持有的锁可以增加其严格性时,才会发生锁转换。)在转换了锁状态之后,锁处于所获取的最高状态,直到持有该锁的事务终止为止。







所有的锁都需要存储空间;因为可用空间并不是无限的,所以 DB2 数据库管理程序必须限制锁可以使用的空间(这是通过 maxlocks 数据库配置参数完成的)。为了防止特定数据库代理超过已建立的锁空间限制,当获取的(任意类型的)锁过多时,会自动执行称为锁升级 的过程。锁升级是一种转换,它将同一表内几个单独的行级锁转换成一个单一的表级锁。因为锁升级是在内部处理的,所以惟一可从外部检测到的结果可能只是对一个和多个表的并发访问减少了。

以下是锁升级的工作原理:当事务请求锁而锁存储空间已满时,就选择与该事务相关联的一个表,让它获取一个表级锁,释放该表的所有行级锁(从而在锁列表数据结构中让出空间),并将表级锁添加到锁列表。如果这个过程所释放的空间不够,则选择另一个表,重复这个过程,直到释放了足够的可用空间为止。这时,事务将获取所请求的锁并继续执行。但是,如果在该事务的所有行级锁都已经升级之后,仍然没有获得必要的可用锁空间,则(通过 SQL 错误编码)要求事务提交或回滚它启动以来所做的所有更改,然后事务终止。







每当一个事务在特定数据资源(例如,表或行)上持有锁时,直到持有锁的事务终止并释放它所获取的所有锁之前,其他事务对该资源的访问都可能被拒绝。如果没有某种锁超时检测机制,则事务可能无限期地等待锁的释放。例如,有可能出现这种情况:一个事务在等待另一个用户的应用程序所持有的锁被释放,而该用户离开了他或她的工作站,但忘了执行一些允许应用程序终止拥有锁的事务的交互。显然,此类情况会导致极差的应用程序性能。要避免发生此类情况时阻碍其他应用程序的执行,可以在数据库的配置文件中指定锁超时值(通过 locktimeout 数据库配置参数)。该参数控制任何事务等待获取所请求的锁的时间。如果在指定的时间间隔过去之后还未获得想要的锁,则等待的应用程序接收一个错误,并回滚请求该锁的事务。分布式事务应用程序环境尤其容易产生此类情况;可以通过使用锁超时避免它们。







尽管可以通过建立锁超时来避免一个事务无限期地等待另一个事务释放锁的情况,但是锁超时无法解决两个或更多事务对锁的争用。这种情况称为死锁死锁循环。说明死锁的发生原因的最佳方式是举例说明:假定事务 1 在表 A 上获取了互斥(X)锁,而事务 2 在表 B 上获取了互斥(X)锁。现在,假定事务 1 尝试在表 B 上获取互斥(X)锁,而事务 2 尝试在表 A 上获取互斥(X)锁。这两个事务的处理都将被挂起,直到同意第二个锁请求为止。但是,因为在任何一个事务释放它目前持有的锁(通过执行或回滚操作)之前,这两个事务的锁请求都不会被同意,而且因为这两个事务都不能释放它目前持有的锁(因为它们都已挂起并等待锁),所以它们都陷入了死锁循环。图 7 说明了这个死锁场景。



死锁循环

当死锁循环发生时,除非某些外部代理进行干涉,否则所涉及的所有事务将无限期地等待释放锁。在 DB2 UDB 中,用于处理死锁的代理是称为死锁检测器 的异步系统后台进程。死锁检测器的惟一职责是定位和解决在锁定子系统中找到的任何死锁。每个数据库有自己的死锁检测器,它在数据库初始化过程中激活。激活之后,死锁检测器在大多数时间处于 “休眠” 状态,但会以预置的时间间隔被 “唤醒”,以确定锁定子系统中是否存在死锁循环。如果死锁检测器在锁定子系统中发现死锁,则随机选择死锁涉及的一个事务,终止并回滚它。选择的事务收到一个 SQL 错误编码,它所获得的所有锁都被释放;这样,剩下的事务就可以继续执行了,因为死锁循环已经被打破了。







正如先前提到的,每当一个事务在特定数据资源上持有锁时,在持有锁的事务终止之前,其他事务对该资源的访问都可能被拒绝。因此,为了进行优化以获取最大的并发性,行级锁通常比表级锁更好,因为它们所限制访问的资源要小得多。但是,因为所获取的每个锁都需要一定数量的处理时间和存储空间,才能获取锁并进行管理,所以单个表级锁需要的开销比几个单独的行级锁少。除非另外指定,否则默认情况下获取行级锁。

可以通过使用 ALTER TABLE ... LOCKSIZE TABLE、ALTER TABLE ... LOCKSIZE ROW 和 LOCK TABLE 语句控制锁的粒度(即,获取行级锁还是表级锁)。ALTER TABLE ... LOCKSIZE TABLE 语句提供了确定粒度的全局方法,它使得所有访问特定表中行的事务都获取表级锁。另一方面,LOCK TABLE 语句允许在单个事务级别获取表级锁。在使用这两种语句时,事务在需要锁时就获取单个共享(S)或互斥(X)表级锁。结果,因为只需获取和释放一个表级锁,而不是多个不同的行级锁,所以锁定性能通常会提高。但是,在使用表级锁时,如果长时间运行的事务获取互斥而不是共享表级锁,那么并发性会降低。







从锁定的角度来看,所有事务通常归为以下几类之一:

  • 只读:这是指只读性的事务,它们包含 SELECT 语句(它们本质上就是只读的)、指定了 FOR READ ONLY 子句的 SELECT 语句或意义虽不明确但因为在预编译和/或绑定过程中指定了 BLOCKING 选项而看作是只读的 SQL 语句。
  • 倾向于更改:这是指有可能进行更改的事务,它们包含指定了 FOR UPDATE 子句的 SELECT 语句或者那些意义虽不明确但因为 SQL 预编译器解释它的方式而看作是倾向于进行更改的 SQL 语句。
  • 更改:这是指一定会进行更改的事务,它们包含 INSERT、UPDATE 和/或 DELETE 语句,但不包括 UPDATE ... WHERE CURRENT OF ... 或 DELETE ... WHERE CURRENT OF ... 语句。
  • 游标控制:这是指包含 UPDATE ... WHERE CURRENT OF ... 和 DELETE ... WHERE CURRENT OF ... 语句的事务。

只读事务通常使用意向共享(IS)和/或共享(S)锁。另一方面,倾向于更改的事务将更新(U)、意向互斥(IX)和互斥(X)锁用于表,将共享(S)、更新(U)和互斥(X)锁用于行。更改事务往往使用意向互斥(IX)和/或互斥(X)锁,而游标控制的事务通常使用意向互斥(IX)和/或互斥(X)锁。

当 SQL 语句准备执行时,DB2 优化器研究各种满足该语句请求的方法,并估计每种方法所涉及的执行成本。然后,DB2 优化器根据这一评估选择它认为最优的访问计划(访问计划指定满足 SQL 请求所需的操作,以及执行这些操作的顺序)。访问计划可以使用两种方法之一来访问表中的数据:通过直接地读取表(称为执行关系扫描);或通过读取该表上的索引,然后检索特定索引项所引用的表行(称为执行索引扫描)。

DB2 优化器选择的访问路径(通常是根据数据库的设计确定的)会对所获取锁的数目和所使用的锁状态产生显著的影响。例如,当使用索引扫描来查找特定行时,DB2 数据库管理程序极有可能获取一个或多个意向共享(IS)行级锁。但是,如果使用表扫描,因为必须依次扫描整个表来找到特定行,所以 DB2 数据库管理程序可能会选择获取单个共享(S)表级锁。

阅读(107670) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~