技术开发 频道

DB2 V9表压缩


对新表使用数据行压缩(表压缩):

    数据行压缩的目标是节省磁盘存储空间。它还可以减少磁盘I/O。另外,可以在缓冲池中高速缓存更多数据,这样就可以提高缓冲池命中率。但是,关联的成本以压缩和解压缩数据所需的额外CPU周期形式出现。数据行压缩节省的存储量和对性能的影响与数据库中数据的特征、数据库的布局和调整以及应用程序工作负载相关。仅压缩数据页上的数据或日志记录中的数据。数据行压缩使用基于静态字典的压缩算法来逐行压缩数据。在行级别压缩数据允许将一行中跨多个列值的重复模式替换为较短的符号字符串。为了压缩表数据,表COMPRESS属性必须设置为YES,且该表必须有压缩字典。要把表设置成压缩方式,使用下列两个命令之一: 
CREATE TABLE table_name . . . COMPRESS YES OR ALTER TABLE tablename COMPRESS YES

    我们接下来创建示例表TEST1,表数据将存储在表空间TABLESPACE1中,其将启用表压缩功能(数据行压缩)。在DB2CLP窗口中,连上示例数据库DB2TEST1,发出CREATE TABLE命令创建带COMPRESS属性的示例表TEST1,具体如清单5所示:
- - 清单5 .创建示例表TEST1 C:\> DB2 CREATE TABLE TEST1 ( ID INTEGER , NAME VARCHAR ( 10 ) , DEPARID VARCHAR ( 10 ) , NOTE VARCHAR ( 100 ) ) IN TABLESPACE1 COMPRESS YES DB20000I SQL命令成功完成。

    命令执行成功,这样我们就创建了示例表TEST1,其启用了数据行压缩方式。要使压缩生效,我们需要要构建压缩字典并接着压缩表(表中需要有数据,不能是空表),然后DB2将扫描表中的数据,找出相同的字符串替换为较短的符号字符串,并放入到压缩字典中。表中的所有数据行都将参与构建压缩字典。该字典将与表数据行一起存储在表数据对象部分。为了构建压缩字典,我们可以使用REORG命令,执行脱机重组。第一次压缩一个表(或者你需要重新构建压缩字典)你可以使用如下命令:

REORG table table_name resetdictionary

    这个命令将扫描整个表,创建压缩字典,然后执行实际表的重组,并在重组的过程中压缩数据。需要注意此时REORG使用的是RESETDICTIONARY选项。如果表的COMPRESS属性为YES并且字典存在,则可能会压缩插入到页中的数据行。此情况适用于任何插入行操作,包括通过导入或装入操作来插入。压缩是对整个表启用的,但却是单独地压缩每行。因此,一个表可以同时包含已压缩的行和未压缩的行。以后如果你需要运行一个正常的表重组,但是有不希望重新构建压缩字典,可以运行下面的命令:

REORG table table_name keepdictionary

    需要注意此时REORG使用的是KEEPDICTIONARY选项。每个表都拥有自己的压缩字典。只能压缩永久数据对象。数据行压缩不适用于索引、长整型数据对象、LOB 数据对象和XML数据对象。行压缩与表数据复制支持不兼容。

    下面我们将为清单5中创建的示例表TEST1创建一个压缩字典。 

    在DB2CLP窗口中,发出REORG命令,脱机执行表重组命令。当示例表TEST1是空表时,执行REORG命令时会报SQL2220W错误,构建压缩字典失败,这是因为示例表TEST1中需要有部分数据时创建压缩字典才会成功,否则压缩字典将无法构建。具体如清单6所示: 

- - 清单6 .对示例表TEST1创建压缩字典 C:\> db2 REORG TABLE test1 resetdictionary SQL2220W 没有为一个或多个数据对象构建压缩字典。 C:\> db2 ? sql2220w SQL2220W 没有为一个或多个数据对象构建压缩字典。 解释: 未能为一个或多个数据对象构建压缩字典。这些对象不包含任何记录,或者不包含大于适合于此页大小的最小记录长度的任何记录。未构建新字典。将继续完成该操作。如果在执行该操作之前已经有一个字典,则会保留该字典,而行数将取决于压缩程度。 用户响应: 参阅“管理日志”以确保是那些数据对象导致了警告。

    为了构建压缩字典,我们需要先为示例表TEST1插入部分数据。 

    在DB2CLP窗口中,连上示例数据库DB2TEST1,在示例表TEST1插入部分数据,部门编号都是‘001’,备注信息都是‘TEST’,编号和姓名都不相同,具体如清单7所示: 

- - 清单7 .对示例表TEST1插入部分数据 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 1 , ' AA ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 2 , ' BB ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 3 , ' CC ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 4 , ' DD ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 5 , ' EE ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 6 , ' FF ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 7 , ' GG ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 8 , ' HH ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 9 , ' II ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。


    命令成功完成,这样我们为示例表TEST1插入了9条记录。部门编号都是‘001’,备注信息都是‘TEST’,编号和姓名都不相同。
下面我们对示例表TEST1创建一个压缩字典,由于是第一次构建压缩字典,所以需要执行带RESETDICTIONARY选项的REORG命令。 

    在DB2CLP窗口中,对示例表TEST1发出REORG命令,执行脱机重组,为示例表TEST1构建压缩字典,具体如清单8所示: 

- - 清单8 .对示例表TEST1创建压缩字典 C:\> db2 REORG TABLE test1 resetdictionary DB20000I REORG命令成功完成。


    命令成功完成,这个命令将扫描整个表,创建压缩字典,然后执行实际表的重组,并在重组的过程中压缩数据。由于部门编号和备注信息各行的数据都相同,所以将DB2通过分析与获取数据中出现的重复模式,生成压缩字典。 

    接下来我们继续对示例表TEST1插入数据,由于示例表TEST1的COMPRESS属性为YES并且字典存在,所以可能会压缩插入到页中的数据行。此情况适用于任何插入行操作,包括通过导入或装入操作来插入。 

    在DB2CLP窗口中,对示例表TEST1通过INSERT INTO命令插入剩余10条数据,具体如清单9所示: 

- - 清单9 .对示例表TEST1插入数据 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 10 , ' JJ ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 11 , ' KK ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 12 , ' LL ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 13 , ' MM ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 14 , ' NN ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 15 , ' OO ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 16 , ' PP ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 17 , ' QQ ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 18 , ' RR ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。 C:\> DB2 INSERT INTO TEST1( ID , NAME , DEPARID , NOTE ) VALUES ( 19 , ' SS ' , ' 001 ' , ' TEST ') DB20000I SQL命令成功完成。


    命令成功完成,新插入的10条记录在数据库中也将以压缩的方式存储。 

    如果想估计对示例表TEST1使用表压缩(数据行压缩)比不使用表压缩节省了多少空间,可以通过INSPECT ROWCOMPESTIMATE语句进行评估分析。记住,这个命令只是估计压缩的效果,而不是查看最终实际的压缩效果,如果想查看实际的压缩效果,需要查看系统表SYSIBM.SYSTABLES。带压缩估计选项(ROWCOMPESTIMATE)的INSPECT命令,将生成一份报告,描述节省了多少页。语法如下:

DB2 INSPECT ROWCOMPESTIMATE TABLE NAME table_name RESULTS KEEP file_name 

    由于INSPECT命令生成的文件是二进制的,无法直接查看,所以我们需要使用DB2INSPF命令将此文件格式转成可读模式才能查看,具体语法如下:

DB2INSPF file_name output_file_name

下面我们看看我们使用表压缩方式节省了多少空间,在DB2CLP窗口中发出DB2 INSPECT命令,具体如清单10所示: 

- - 清单10 .查看示例表TEST1,看一下表压缩方式节省了多少空间 C:\> DB2 " INSPECT ROWCOMPESTIMATE TABLE NAME test1 RESULTS KEEP test1.resp " DB20000I INSPECT命令成功完成。


    命令成功完成,这样我们就在C:\Program Files\IBM\SQLLIB\DB2下生成了一个文件test1.resp,由于这个文件是二进制的,我们需要使用DB2INSPF将此文件格式转成可读模式才能查看,继续在DB2CLP窗口中执行DB2INSPF命令,具体如清单11所示: 

- - 清单11 .查看示例表TEST1,看一下表压缩方式节省了多少空间 C:\> cd C:\Program Files\IBM\SQLLIB\DB2 C:\Program Files\IBM\SQLLIB\DB2> DB2INSPF test1.resp output_test1.resp


    此时我们打开output_test1.resp文件,可以看到通过压缩而节省的页数所占的百分比是56,通过压缩而节省的字节数所占的百分比是56,由于行大小太小而不适合压缩的行数所占的百分比是0,压缩字典大小是8192个字节,扩充字典大小是3336 个字节,具体如清单12所示: 

- - 清单12 .查看示例表TEST1,看一下表压缩方式节省了多少空间 DATABASE: DB2TEST1 VERSION : SQL09010 2007-10-25-21.14.03.500000 操作:ROWCOMPESTIMATE TABLE 模式名:RHETTE 表名:TEST1 表空间标识:3 对象标识:4 结果文件名:test1.resp 表阶段开始(有符号的标识:4,无符号的:4;表空间标识:3):RHETTE.TEST1 数据阶段开始。对象:4 表空间:3 行压缩估计结果: 通过压缩而节省的页数所占的百分比:56 通过压缩而节省的字节数所占的百分比:56 由于行大小太小而不适合压缩的行数所占的百分比:0 压缩字典大小:8192 个字节。 扩充字典大小:3336 个字节。 数据阶段结束。 表阶段结束。 处理已完成。2007-10-25-21.14.03.562000


    我们可以使用INSPECT ROWCOMPESTIMATE语句对压缩的效果进行评估分析,如果想查看实际的压缩效果,需要查看系统表SYSIBM.SYSTABLES,这系统表中,有几个新增的列是和压缩相关的:

 COMPRESSION:此参数表示对于表来说,是否使用了压缩,其有4个值,含义分别是:
 -N:没有设置任何压缩
 -V:仅仅设置了空间值压缩
 -R:仅仅设置了数据行压缩
 -B:即设置了空间值压缩,也设置了数据行压缩

 AVGROWSIZE:新增列,用来表示表的平均物理行长,包括所有压缩和没有压缩的数据行,此参数用来决定每页能存放的最大行数(对常规表空间来说,单页最大能放255行,对于大型表空间来说,单页最大行数会超过255行。)。当值为-1的时候,表示统计信息没有收集。

 PCTPAGESSAVED:新增列,表示使用压缩节省空间页的百分比。当值为-1的时候,表示统计信息没有收集。

 PCTROWSCOMPRESSED:新增列,表示表中压缩的行数占总行数的百分比。这个参数用来决定解压缩时CPU的开支。当值为-1的时候,表示统计信息没有收集。

 AVGROWCOMPRESSIONRATIO:新增列,表示所有压缩的行的平均压缩比例(是压缩前的总页数和压缩后的总页数的比例)。当值为-1的时候,表示统计信息没有收集。

 AVGCOMPRSSEDROWSIZE:新增列,表示所有压缩行在物理磁盘上的平均物理行长,当值为-1的时候,表示统计信息没有收集。 

    另外,需要注意的是,如果想查看SYSIBM.SYSTABLES表中某个表的压缩情况,需要要查询都是表运行RUNSTATS,只有这样,上述几个列的值才不会是-1。 

    下面,我们在DB2CLP窗口中,发出RUNSTATS命令对示例表TEST1运行统计信息,具体如清单13所示: 

- - 清单13 .对示例表TEST1运行统计信息 C:\> DB2 RUNSTATS ON TABLE RHETTE.TEST1 DB20000I RUNSTATS命令成功完成。


    接下来我们就可以通过系统表SYSIBM.SYSTABLES查看示例表TEST1的压缩情况了。 

    我们继续在DB2CLP窗口中,发出SELECT命令查看示例表TEST1的压缩情况,具体如清单14所示: 

- - 清单14 .查看示例表TEST1压缩情况 C:\> DB2 SELECT NAME , COMPRESSION , AVGROWSIZE , PCTPAGESSAVED , PCTROWSCOMPRESSED ,AVGROWCOMPRESSIONRATIO , AVGCOMPRESSEDROWSIZE FROM SYSIBM.SYSTABLES WHERE NAME = 'TEST1' NAME COMPRESSION AVGROWSIZE PCTPAGESSAVED PCTROWSCOMPRESSED AVGROWCOMPRESSIONRATIO AVGCOMPRESSEDROWSIZE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TEST1 R 19 56 100 2.29223 19 1 条记录已选择。


    可以看到示例表TEST1启用了数据行压缩,压缩后的所有行的平均行长是19,压缩后节省空间的百分比是56%和用INSPECT命令估计的一样,压缩的行数占总行数的百分比是100%,压缩前和压缩后页数的百分比是2.29223,压缩行的平均行长是19。
如果想查看压缩字典的大小,可以使用ADMIN_GET_TAB_INFO表函数查看其DICTIONARY_SIZE列的值,比如我们想查看示例表TEST1的压缩字典大小,可以在DB2CLP窗口中这么查看,具体如清单15所示: 

- - 清单15 .查看示例表TEST1压缩字典大小 C:\>db2 describe "select * from table(sysproc.admin_get_tab_info('rhette','test1')) as t" SQLDA 信息 sqldaid : SQLDA sqldabc: 1204 sqln: 27 sqld: 27 列信息 sqltype sqllen sqlname.data sqlname.length - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 449 VARCHAR 128 TABSCHEMA 9 449 VARCHAR 128 TABNAME 7 453 CHARACTER 1 TABTYPE 7 501 SMALLINT 2 DBPARTITIONNUM 14 497 INTEGER 4 DATA_PARTITION_ID 17 453 CHARACTER 1 AVAILABLE 9 493 BIGINT 8 DATA_OBJECT_L_SIZE 18 493 BIGINT 8 DATA_OBJECT_P_SIZE 18 493 BIGINT 8 INDEX_OBJECT_L_SIZE 19 493 BIGINT 8 INDEX_OBJECT_P_SIZE 19 493 BIGINT 8 LONG_OBJECT_L_SIZE 18 493 BIGINT 8 LONG_OBJECT_P_SIZE 18 493 BIGINT 8 LOB_OBJECT_L_SIZE 17 493 BIGINT 8 LOB_OBJECT_P_SIZE 17 493 BIGINT 8 XML_OBJECT_L_SIZE 17 493 BIGINT 8 XML_OBJECT_P_SIZE 17 501 SMALLINT 2 INDEX_TYPE 10 453 CHARACTER 1 REORG_PENDING 13 449 VARCHAR 10 INPLACE_REORG_STATUS 20 449 VARCHAR 12 LOAD_STATUS 11 453 CHARACTER 1 READ_ACCESS_ONLY 16 453 CHARACTER 1 NO_LOAD_RESTART 15 501 SMALLINT 2 NUM_REORG_REC_ALTERS 20 453 CHARACTER 1 INDEXES_REQUIRE_REBUILD 23 453 CHARACTER 1 LARGE_RIDS 10 453 CHARACTER 1 LARGE_SLOTS 11 493 BIGINT 8 DICTIONARY_SIZE 15


    如果觉得压缩的效果不能满意,可以对表进行解压缩,也就是把表的COMPRESS 属性设置为 NO,然后执行传统脱机表重组,这样就把压缩表变成了不压缩的表了。 

    比如,我们现在想对示例表TEST1进行解压缩,可以继续在当前的DB2CLP窗口中,先发出ALTER TABLE命令,把示例表TEST1的COMPRESS属性设置为NO,再运行REORG命令执行脱机重组,具体如清单16所示: 

- - 清单16 .对示例表TEST1进行解压缩 C:\Program Files\IBM\SQLLIB\DB2>cd \ C:\> db2 alter table test1 compress no DB20000I SQL命令成功完成。 C:\> db2 reorg table test1 resetdictionary DB20000I REORG命令成功完成。

    命令成功完成,此时示例表TEST1将不再使用表压缩功能,并且压缩字典将被删除。此时我们再次在DB2CLP窗口中查看示例表TEST1的实际压缩情况,可以发现,没有使用压缩,有关压缩的各个列都和压缩的时候值不一样了,具体如清单17所示:

- - 清单17 .查看示例表TEST1压缩情况 C:\> DB2 SELECT NAME , COMPRESSION , AVGROWSIZE , PCTPAGESSAVED , PCTROWSCOMPRESSED ,AVGROWCOMPRESSIONRATIO , AVGCOMPRESSEDROWSIZE FROM SYSIBM.SYSTABLES WHERE NAME = 'TEST1' NAME COMPRESSION AVGROWSIZE PCTPAGESSAVED PCTROWSCOMPRESSED AVGROWCOMPRESSIONRATIO AVGCOMPRESSEDROWSIZE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TEST1 N 45 0 0 0 0 1 条记录已选择。


总结一下,如果对一个新表启用表压缩:
 -创建一个表,将表的COMPRESS属性设置为 YES
 -对表装入一部分数据
 -执行带有RESETDICTIONARY选项的脱机重组,创建一个新的压缩字典
 -装入剩余的数据到这个表中(装入时将考虑压缩字典并在装入时压缩数据)

0
相关文章