供稿人:刘隶放
内容提要:
通常我们可以使用 list tablespaces show detail 或 db2pd -tablespace命令来检查表空间的使用情况。本文中,我们介绍一种使用DB2工具db2dart详细分析数据库管理表空间(DMS)使用情况的方法。
说明:
首先,我们回顾一下《管理指南:计划》中关于数据库管理表空间的一些说明:
“……
# 在缺省情况下,每个容器中都保留一个扩展数据块作为开销。只使用整个扩展数据块,因此为了对空间进行最优管理,可以使用如下公式来帮助您确定当分配容器时要使用的适当大小:
extent_size * (n + 1)
其中,extent_size 是表空间中每个扩展数据块的大小,而 n 是您要在该容器中存储的扩展数据块数目。
# DMS 表空间的最小大小是五个扩展数据块。试图创建小于五个扩展数据块的表空间将产生错误(SQL1422N)。
- 表空间中有三个扩展数据块是保留给开销使用的。
- 要存储任何用户表数据,至少需要两个扩展数据块。(这些扩展数据块是一个表的规则数据所必需的,但不是任何索引、长型字段或大对象数据所需的,它们需要自己的扩展数据块。)
……
”
上文说明,一个表空间的容器大小至少要为6个扩展块(5+1)才可以存储1个用户表,如下图所示:
| 扩展块* |
容器保留开销 |
| 扩展块0 |
表空间保留开销 |
| 扩展块1 |
表空间保留开销 |
| 扩展块2 |
表空间保留开销 |
| 扩展块3 |
表1的扩展块对应图 |
| 扩展块4 |
表1的第一个数据块 |
| 扩展块5 |
…… |
| …… |
…… |
图1 数据库管理表空间逻辑地址图
另外,在一个扩展块中只能存储一个表的一个数据对象,两个表不能共享一个扩展块,两种数据对象(扩展块对应图,数据,索引,大对象,…)不能共享一个扩展块。
注*
在 list tablespaces show detail ,db2pd - tablespace ,db2dart 的输出中,都是从扩展块0开始计算的。容器保留开销扩展块对应 list tablespaces show detail输出中“总计页数减可用页数”部分。
下面,对比 list tablespaces show detail 的输出,我们探讨一下如何利用db2dart工具分析数据库管理表空间的使用情况。实际上,在使用db2dart工具时,我们使用的是 DHWM 选项。DHWM是 Dumps High Water Mark 的缩写,该选项是为了帮助用户分析数据库管理表空间的高水位标记而设定的,利用此选项,我们可用分析数据库管理表空间的使用情况。
1 创建一个测试用的数据库管理表空间
db2 "create tablespace usrtest managed by database using (device '/dev/rusrsp1' 64M)"
然后,使用 list tablespaces show detail 命令检查一下表空间的使用情况:
db2 list tablespaces show detail
当前数据库的表空间
……
表空间标识 = 4
名称 = USRTEST
类型 = 数据库管理空间
内容 = 任何数据
状态 = 0x0000
详细解释:
正常
总计页数 = 16384
可用页数 = 16352
已用页数 = 96
未用页数 = 16256
高水位标记(页) = 96
页大小(以字节计) = 4096
扩展数据块大小(页) = 32
预取大小(页) = 32
容器数 = 1
……
从上面的输出中我们可以看到,表空间在刚刚创建完以后就已经有32页(16384 —16352)即1个扩展块不可使用,这部分对应图1中容器保留开销扩展块的部分;有96页即3个扩展块已使用,这部分对应图1中扩展块0-2部分,即表空间保留开销。
接下来,使用 db2dart 命令加 DHWM 选项检查一下表空间的使用情况。注意,必须要在实例正常停止的情况下执行db2dart命令,否则可能导致数据库崩溃。
db2dart test /dhwm /tsi 4
The requested DB2DART processing has completed successfully!
Complete DB2DART report found in:
/home/db2inst1/sqllib/db2dump/DART0000/TEST.RPT
打开输出文件 /home/db2inst1/sqllib/db2dump/DART0000/TEST.RPT ,我们看到下面内容:
DART
D a t a b a s e A n a l y s i s a n d R e p o r t i n g T o o l
IBM DB2 6000
DART (V8.1.0) Report:
2006-09-01-10.41.13.211971
Database Name: TEST
Report name: TEST.RPT
Database Subdirectory: /home/db2inst1/db2inst1/NODE0000/SQL00003
Operational Mode: Database Inspection Only (INSPECT)
------------------------------------------------------------------------------------------------------------------------------
Action option: DHWM
Tablespace-ID: 4
Connecting to Buffer Pool Services...
Highwater mark processing - phase start.
NOTES:
All highwater mark values and/or object sizes listed below aregiven in extents and not pages (unless explicitly stated).*1
The object ID and object type are shown for each extent listed.*2
Extents marked with an asterisk (*) hold the first page of an
object and these extents can only be moved by dropping and
recreating that object.*3
Extents marked as belonging to objects with ID equal to 65534 or
65535 are SMP extents or object table extents and they are not
movable.*4
After following a step and before continuing on to the next one,
disconnect and reconnect to the database.
Highwater Mark: 96 pages, 3 extents (extents #0 - 2)
[0000] 65534 0x0e [0001] 65534 0x0e [0002] 65535 0x00
Dump highwater mark processing - phase start.
Number of free extents below highwater mark: 0
Number of used extents below highwater mark: 3
……
注
*1 所有的高水位和数据对象标记都以扩展块为单位。
*2 数据对象和数据类型标记在每一个扩展块中。
*3 星号(*)代表数据对象的第一个扩展块。除非数据对象被删除,否则此类扩展块是无法移动的。
*4 对象ID为65534或65535D的对象为SMP(Space Map Page)扩展块和对象表扩展块,这些扩展块也是不可移动的。这些扩展块就是表空间保留开销。随着数据对象的增加和数据对象中数据量的增加,表空间中可能会创建更多的保留开销扩展块。
从上面的输出可以看到,刚创建完时,数据库管理表空间中只有3个表空间保留开销扩展块:
Highwater Mark: 96 pages, 3 extents (extents #0 - 2)
[0000] 65534 0x0e [0001] 65534 0x0e [0002] 65535 0x00
2 在表空间中创建一个表
db2inst1@p615 /home/db2inst1$ db2 "create table t1 (id int not null, name char(20)) in usrtest"
DB20000I The SQL command completed successfully.
使用 list tablespaces show detail 命令再次检查表空间的使用情况:
db2 list tablespaces show detail
当前数据库的表空间
……
| 表空间标识 |
= 4 |
| 名称 |
= USRTEST |
| 类型 |
= 数据库管理空间 |
| 内容 |
= 任何数据 |
| 状态 |
= 0x0000 |
| 详细解释: |
|
| 正常 |
|
| 总计页数 |
= 16384 |
| 可用页数 |
= 16352 |
| 已用页数 |
= 160 |
| 未用页数 |
= 16192 |
| 高水位标记(页) |
= 160 |
| 页大小(以字节计) |
= 4096 |
| 扩展数据块大小(页) |
= 32 |
| 预取大小(页) |
= 32 |
| 容器数 |
= 1 |
相比前面的输出,表空间中已用的扩展块增加到5个(160页)。用 db2dart 加 DHWM 选项,再次分析该表空间的使用情况:
……
Highwater Mark: 160 pages, 5 extents (extents #0 - 4)
[0000] 65534 0x0e [0001] 65534 0x0e [0002] 65535 0x00 [0003] 4 0x40*
[0004] 4 0x00*
Dump highwater mark processing - phase start.
Number of free extents below highwater mark: 0
Number of used extents below highwater mark: 5
……
相比于前次的输出,增加了下面两个扩展块:
[0003] 4 0x40* [0004] 4 0x00*
| [0003]1 |
42 0x4304*5 |
| [0003]1 |
代表扩展块3 |
| 42 |
代表对象4 |
| 0x43 |
代表该扩展块存储的是该对象扩展块的对应图 |
| 04 |
代表存储的是数据 |
| *5 |
代表这是该对象(扩展块对应图)第一个扩展块。 |
| [0004]1 |
42 0x4304*5 |
| [0004]1 |
代表扩展块4 |
| 42 |
代表对象4 |
| 0x03 |
代表这是对象扩展块 |
| 04 |
代表存储的是数据 |
| *5 |
代表这是该对象第一个扩展块。 |
3 在表 t1 上创建一个索引
db2 "create index i1 on t1(id)" list tablespaces show detail 的输出显示,表空间中已用的扩展块增加到7个(224页)
db2 list tablespaces show detail
当前数据库的表空间 ……
| 表空间标识 |
= 4 |
| 名称 |
= USRTEST |
| 类型 |
= 数据库管理空间 |
| 内容 |
= 任何数据 |
| 状态 |
= 0x0000 |
| 详细解释: |
|
| 正常 |
|
| 总计页数 |
= 16384 |
| 可用页数 |
= 16352 |
| 已用页数 |
= 224 |
| 未用页数 |
= 16128 |
| 高水位标记(页) |
= 224 |
| 页大小(以字节计) |
= 4096 |
| 扩展数据块大小(页) |
= 32 |
| 预取大小(页) |
= 32 |
| 容器数 |
= 1 |
用 db2dart 加 DHWM 选项,分析这时候表空间的使用情况:
……
Highwater Mark: 224 pages, 7 extents (extents #0 - 6)
[0000] 65534 0x0e [0001] 65534 0x0e [0002] 65535 0x00 [0003] 4 0x40*
[0004] 4 0x00* [0005] 4 0x41* [0006] 4 0x01*
Dump highwater mark processing - phase start.
Number of free extents below highwater mark: 0
Number of used extents below highwater mark: 7
……
相比于前次的输出,表空间中又增加了下面两个扩展块:
[0005] 4 0x41* [0006] 4 0x01*
| [0005]1 |
42 0x4314*5 |
| [0005]1 |
代表扩展块5 |
| 42 |
代表对象4 |
| 0x43 |
代表该扩展块存储的是该对象扩展块的对应图 |
| 04 |
代表存储的是索引 |
| *5 |
代表这是该对象(扩展块对应图)第一个扩展块。 |
| [0004]1 |
42 0x0314*5 |
| [0004]1 |
代表扩展块6 |
| 42 |
代表对象4 |
| 0x03 |
代表这是对象扩展块 |
| 04 |
代表存储的是索引 |
| *5 |
代表这是该对象第一个扩展块。 |
4 在表 t1 中插入一些数据
db2 "insert into t1 with c1(col1) as(values(1) union all select c1.col1 + 1 from c1 where c1.col1<50000 ) select c1.col1,'testing' from c1"
用 db2dart 加 DHWM 选项,分析此时表空间的使用情况:
……
Highwater Mark: 864 pages, 27 extents (extents #0 - 26)
[0000] 65534 0x0e [0001] 65534 0x0e [0002] 65535 0x00 [0003] 4 0x40*
[0004] 4 0x00* [0005] 4 0x41* [0006] 4 0x01* [0007] 4 0x00
[0008] 4 0x00 [0009] 4 0x01 [0010] 4 0x00 [0011] 4 0x00
[0012] 4 0x01 [0013] 4 0x00 [0014] 4 0x00 [0015] 4 0x01
[0016] 4 0x00 [0017] 4 0x00 [0018] 4 0x00 [0019] 4 0x01
Dump highwater mark processing - phase start.
Number of free extents below highwater mark: 0
Number of used extents below highwater mark: 27
……
相当于前次输出,表空间中增加了下面扩展块: [0007] 4 0x00 [0008] 4 0x00 [0009] 4 0x01 [0010] 4 0x00 [0011] 4 0x00
[0012] 4 0x01 [0013] 4 0x00 [0014] 4 0x00 [0015] 4 0x01
[0016] 4 0x00 [0017] 4 0x00 [0018] 4 0x00 [0019] 4 0x01
[0020] 4 0x00 [0021] 4 0x00 [0022] 4 0x01 [0023] 4 0x00
[0024] 4 0x00 [0025] 4 0x01 [0026] 4 0x00
其中,扩展块 7,8,10,11,13,14,16,17,18,20,21,23,24,26存储的是数据,9,12,15,19,22,25存储的是索引。当然,这些扩展块都不再是第一个扩展块。
5 使用 db2dart 研究表空间使用情况的实际应用
笔者在实际工作中遇到过一个这样的问题:从 list tablespaces show detail 的输出来看,表空间中已用页数为457088;而从某第三方数据库管理工具来看,如图2所示,表(Tables)占用的空间仅为14.55%,80.63的空间使用情况标记为其它(Other)。
db2 list tablespaces show detail
当前数据库的表空间
……
| 表空间标识 |
= 4 |
| 名称 |
= xxxxxxx |
| 类型 |
= 数据库管理空间 |
| 内容 |
= 任何数据 |
| 状态 |
= 0x0000 |
| 详细解释: |
|
| 正常 |
|
| 总计页数 |
= 457152 |
| 可用页数 |
= 457088 |
| 已用页数 |
= 435072 |
| 未用页数 |
= 22016 |
| 高水位标记(页) |
= 456192 |
| 页大小(以字节计) |
= 16384 |
| 扩展数据块大小(页) |
= 64 |
| 预取大小(页) |
= 384 |
| 容器数 |
= 1 |
……

图2 第三方工具显示的表空间使用情况
为什么会出现这种情况呢?经过研究发现,第三方工具显示的表空间使用情况中,表(Tables)占用空间大小与系统视图SYSCAT.TABLES里NPAGES的累加值相匹配。
db2 “select sum(NPAGES) from syscat.tables where tbspaceid=4”
1
-----------
66516
1 条记录已选择。
66516 / 457152 * 100% = 14.55%
注意,执行上面SQL语句前,应保证系统视图SYSCAT.TABLES里包含所有在此表空间中的表的最新统计信息。
此类问题可用 db2dart 工具来分析。db2dart 加 DHWM 选项的输出如下:
……
Highwater Mark: 456192 pages, 7128 extents (extents #0 - 7127)
[0000] 65534 0x0e [0001] 65534 0x0e [0002] 65535 0x00 [0003] 4339 0x40*
[0004] 3045 0x40* [0005] 4339 0x00* [0006] 3045 0x00* [0007] 2048 0x40*
[0008] 2048 0x00* [0009] 4340 0x40* [0010] 2767 0x40* [0011] 2767 0x00*
[0012] 3081 0x40* [0013] 3081 0x00* [0014] 3944 0x40* [0015] 3944 0x00*
[0016] 4379 0x40* [0017] 4379 0x00* [0018] 2257 0x40* [0019] 2257 0x00*
[0020] 4399 0x40* [0021] 4399 0x00* [0022] 4340 0x00* [0023] 4341 0x40*
[0024] 64 0x40* [0025] 64 0x00* [0026] 4379 0x00 [0027] 4379 0x00
[0028] 4399 0x00 [0029] 4429 0x40* [0030] 4429 0x00* [0031] 4434 0x40*
[0032] 2316 0x40* [0033] 2316 0x00* [0034] 4434 0x00* [0035] 4447 0x40*
[0036] 2361 0x40* [0037] 4103 0x40* [0038] 4103 0x00* [0039] 2361 0x00*
[0040] 2362 0x40* [0041] 2362 0x00* [0042] 2363 0x40* [0043] 2363 0x00*
[0044] 2364 0x40* [0045] 2364 0x00* [0046] 4341 0x00* [0047] 4342 0x40*
[0048] 4355 0x40* [0049] 4342 0x00* [0050] 4355 0x00* [0051] 4356 0x40*
[0052] 4104 0x40* [0053] 36 0x40* [0054] 36 0x00* [0055] 4104 0x00*
[0056] 2075 0x40* [0057] 2075 0x00* [0058] 4343 0x40* [0059] 2077 0x40*
[0060] 4344 0x40* [0061] 2406 0x40* [0062] 2406 0x00* [0063] 2272 0x40*
[0064] 2272 0x00* [0065] 90 0x40* [0066] 4343 0x00* [0067] 4344 0x00*
[0068] 4345 0x40* [0069] 4345 0x00* [0070] 4179 0x40* [0071] 4179 0x00*
[0072] 4356 0x00* [0073] 4357 0x40* [0074] 4447 0x00* [0075] 4529 0x40*
[0076] 73 0x40* [0077] 4367 0x40* [0078] 4346 0x40* [0079] 4357 0x00*
[0080] 3042 0x40* [0081] 3042 0x00* [0082] 4180 0x40* [0083] 4180 0x00*
[0084] 73 0x00* [0085] 4346 0x00* [0086] 4347 0x40* [0087] 74 0x40*
[0088] 2580 0x40* [0089] 4348 0x40* [0090] 74 0x00* [0091] 3082 0x40*
[0092] 4103 0x00 [0093] 4104 0x00 [0094] 4104 0x00 [0095] 4105 0x40*
[0096] 2305 0x40* [0097] 2305 0x00* [0098] 2433 0x40* [0099] 2433 0x00*
[0100] 4347 0x00* [0101] 4348 0x00* [0102] 2580 0x00* [0103] 2581 0x40*
[0104] 76 0x40* [0105] 2581 0x00* [0106] 2883 0x40* [0107] 2883 0x00*
[0108] 532 0x40* [0109] 532 0x00* [0110] 2435 0x40* [0111] 2435 0x00*
[0112] 3082 0x00* [0113] 3083 0x40* [0114] 76 0x00* [0115] 2585 0x40*
[0116] 4181 0x40* [0117] 4181 0x00* [0118] 3083 0x00* [0119] 4349 0x40*
[0120] 4179 0x00 [0121] 4182 0x40* [0122] 3084 0x40* [0123] 3084 0x00*
[0124] 2769 0x40* [0125] 2769 0x00* [0126] 4358 0x40* [0127] 4358 0x00*
[0128] 2436 0x40* [0129] 3085 0x40* [0130] 3085 0x00* [0131] 2367 0x40*
[0132] 2367 0x00* [0133] 2436 0x00* [0134] 22 0x40* [0135] 22 0x00*
[0136] 2205 0x40* [0137] 3086 0x40* [0138] 3086 0x00* [0139] 4349 0x00*
[0140] 2077 0x00* [0141] 2123 0x40* [0142] 2123 0x00* [0143] 97 0x40*
[0144] 97 0x00* [0145] 2205 0x00* [0146] 2125 0x40* [0147] 4351 0x40*
[0148] 2369 0x40* [0149] 2369 0x00* [0150] 94 0x40* [0151] 4359 0x40*
[0152] 4359 0x00* [0153] 94 0x00* [0154] 2371 0x40* [0155] 4351 0x00*
[0156] 4352 0x40* [0157] 4367 0x00* [0158] 4368 0x40* [0159] 2371 0x00*
[0160] 2372 0x40* [0161] 2372 0x00* [0162] 149 0x40* [0163] 2125 0x00*
[0164] 2130 0x40* [0165] 149 0x00* [0166] 4352 0x00* [0167] 2130 0x00*
[0168] 2137 0x40* [0169] 150 0x40* [0170] 150 0x00* [0171] 3087 0x40*
[0172] 3087 0x00* [0173] 4353 0x40* [0174] 4366 0x40* [0175] 129 0x40*
[0176] 2137 0x00* [0177] 2138 0x40* [0178] 2138 0x00* [0179] 2146 0x40*
[0180] 2146 0x00* [0181] 2179 0x40* [0182] 4353 0x00* [0183] 4354 0x40*
[0184] 2377 0x40* [0185] 4354 0x00* [0186] 2377 0x00* [0187] 3605 0x40*
[0188] 4360 0x40* [0189] 2236 0x40* [0190] 4105 0x00* [0191] 4106 0x40*
[0192] 3605 0x00* [0193] 4529 0x00* [0194] 4532 0x40* [0195] 2179 0x00*
[0196] 4360 0x00* [0197] 2236 0x00* [0198] 4361 0x40* [0199] 3088 0x40*
[0200] 3088 0x00* [0201] 2125 0x00 [0202] 2186 0x40* [0203] 2440 0x40*
……
……
……
[7100] 1850 0x00* [7101] 1853 0x40* [7102] 3929 0x40* [7103] 1853 0x00*
[7104] 1859 0x40* [7105] 1859 0x00* [7106] 1860 0x40* [7107] 1860 0x00*
[7108] == EMPTY == [7109] 3033 0x40* [7110] 3033 0x00* [7111] == EMPTY ==
[7112] 3797 0x00* [7113] 3929 0x00* [7114] 1861 0x40* [7115] 3930 0x40*
[7116] 3930 0x00* [7117] 1861 0x00* [7118] 1862 0x40* [7119] 3932 0x40*
[7120] 3932 0x00* [7121] 1862 0x00* [7122] 1864 0x40* [7123] 3934 0x40*
[7124] 3934 0x00* [7125] 1864 0x00* [7126] 1865 0x40* [7127] 1865 0x00*
Dump highwater mark processing - phase start.
Number of free extents below highwater mark: 497
Number of used extents below highwater mark: 6631
……
注: == EMPTY == 代表该扩展块内没有数据。
分析上面的输出可以发现,大量扩展块标有星号(*)。该表空间容器中高水位下共有7127个扩展块,而带有星号的扩展块共有6018个。其中3009个扩展块为0x40*,3009个为0x00*。前面提到过,星号代表数据对象的第一个扩展块,所以该表空间容器中有大量的表中的数据不超过1个扩展块。结合 select count(*) from <tablename> 命令发现,很多表中只含有少量数据(只占用一页),有的表中甚至只有一行数据。这会带来空间上很大的浪费:
- 一个扩展块只能储存一个表的一种数据对象。在这个例子中,很多表只占用了一页,对于此类扩展块(扩展数据块大小为64),有98.4%(63/64)的空间被浪费掉。
- 由于每一个表至少需要一个扩展块记录扩展块对应图,而很多记录扩展块对应图的扩展块只记录了表使用的一个扩展块,这也造成了很大的空间浪费。
针对上述问题,用户应该考虑将这些数据量比较小的表放在使用较小的“扩展数据块大小”,甚至较小的“页大小”的表空间中,以避免空间上的浪费。
结论
我们利用 db2dart 提供的 DHWM 选项配合 list tablespaces show detail 命令可以精确分析数据库管理表空间的使用情况。
参考资料:
《管理指南:计划》