使用 DB2 10 中的深度压缩来优化存储

使用深度压缩最大程度地减少存储空间和提高数据库性能

组织现在正在生成比以往任何时候都要多的数据。而且遵守法律和政府制度的要求意味着他们需要将该数据保留更长的时间。结果导致数据库正以惊人的速度增长。事实上,依据行业分析师的分析,企业数据正在以每年 125% 的速度增长。这一爆炸式的数据增长为企业带来了存储、保护、分配生成的所有数据并从中获取的价值的巨大压力。在 2007 年,IBM® 通过在 DB2® 9 中引入新的压缩技术(称为深度压缩)减轻了这一压力。自那以后,IBM 在后续的 DB2 版本中改进了这项技术。本文将介绍 DB2 Version 10.1 中提供的各种压缩方法,还将提供一些建议的 “最佳实践”,在您采用任何压缩技术时,这些最佳实践会帮助您实现最大的存储空间节省。

Roger E. Sanders, 咨询公司系统工程师, EMC Corporation

Roger SandersRoger E. Sanders (roger_e_sanders@yahoo.com) 是 bC Corporation 的一位高级咨询公司系统工程师,撰写了 21 本关于 DB2 for Linux, UNIX, and Windows 的书籍,是 2011 IBM Information Champion 的获奖者。他的新书的标题是《From Idea to Print: How to Write a Technical Article or Book and Get It Published》。


developerWorks 专家作者

Thomas Fanghaenel, 高级软件工程师, IBM

Fanghaenel Thomas Fanghaenel 已为 IBM 工作了 9 年,是 DB2 Data Warehouse Storage and Indexing Development 团队的一名高级软件工程师。过去 5 年来,他一直从事 DB2 for Linux, UNIX and Windows 开发,专门研究关系和原生 XML 存储引擎中的压缩功能。Thomas 领导过 DB2 10 中的自适应行压缩开发团队。在参与研究 DB2 for Linux, UNIX, and Windows 之前,Thomas 是 DB2 Everyplace(IBM 面向迁移和嵌入式系统的原始数据库产品)的技术领导。过去,Thomas 曾在加利福尼亚州圣何塞和中国北京的 IBM 部门工作过。他目前住在马萨诸塞州马尔伯勒。



2012 年 7 月 30 日

免费下载:IBM® DB2® Express-C 10.1 免费版 或者 DB2® 10.1 for Linux®, UNIX®, and Windows® 试用版
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

数据的性质

无论您信不信,尽管数据量在增加,但数据的基数却有下降的趋势。结果是,世界上没有多少真正惟一的事物。一些事物可能在结合使用时变得惟一,但基本元素本身并没有什么不同。请想想元素周期表 — 我们世界的万事万物都由很少的元素组合而成。如果将这一概念应用到数据上,您会发现完全适用。例如,依据最新的美国人口普查,有大约 3 亿人生活在美国。但只有大约 78,800 个惟一的姓氏,结果是某些姓名集合拥有大量的使用人群,但基数却非常小。名字的情况更糟,只有大约 6,600 个名字(4,400 个惟一的名称供女性使用,2,200 个惟一名称供男性使用)。城市、街道和地址的名称(更别提产品名称、描述和属性)也可能高度重复,拥有很小的基数。

深度压缩的工作原理

深度压缩基于大量数据可能是高度重复的这一原理。它搜索数据中重复出现的模式并将这些替换为 12 位的符号,这些符号与它们所表示的模式一起存储在一个静态字典中。创建此字典后,该字典就会与压缩的数据一起存储在表(或页面)中,在访问表中的数据时,就会将这些字典加载到内存中(以帮助解压)。当启用深度压缩时,DB2 会扫描整个表,查找重复的列值以及在一行或一页中的多列中出现的重复模式。它还会查找给定的一列中的子字符串的重复模式。但是,只找到了一个重复模式,并不意味着会对数据进行自动压缩。仅在能够节省存储时才会对数据进行压缩。在任何情况下,整个一行都会存储为一组 12 位符号;绝不会对每一行进行部分压缩。

深度压缩可应用于主要的用户数据(行数据、XML 数据和索引)、系统生成的数据(临时表)和管理数据(备份映像和归档的事务日志)。DB2 软件的所有版本中都提供了针对管理数据的压缩工具。针对主要的用户数据和系统生成的数据的高级压缩特性可通过 DB2 Storage Optimization Feature 获取。


备用行的格式

在创建用户定义的表时,有两种格式可供使用:标准备用,您选择的格式决定了行在存储到磁盘上时的压缩方式。备用行格式允许更紧凑地存储 NULL 值、系统默认值,以及具有可变长度数据类型的列中的零长度的值。(DB2 可识别的可变长度数据类型包括 VARCHAR、VARGRAPHIC、LONG VARCHAR、LONG VARGRAPHIC、BLOB、CLOB、DBCLOB 和 XML。)因此,此格式常常称为 NULL 和默认值压缩,或者简单地称为值压缩

使用标准的行格式,会为固定长度列值分配空间,即使实际存储的值为 NULL。类似地,具有可变长度数据类型的列中存储的零长度的值会使用少量的空间。但在使用备用行格式时,所有列中的 NULL 值和具有可变长度数据类型的列中的零长度值不会使用任何空间。

与标准行格式相比,备用行格式还会减少具有可变长度数据类型的列中所有其他值的存储开销。但是,存储在固定长度列中的所有非 NULL 值所使用的存储空间会增加。确定具有所有支持的数据类型的值的字节数和行格式的公式均可在 CREATE TABLE 语句的参考材料中找到。

控制行格式

您可以控制每个表上使用的行格式。默认情况下,表使用的是标准行格式。要创建使用备用行格式的表,只需将 VALUE COMPRESSION 子句附加到创建表的 CREATE TABLE 语句中。例如:CREATE TABLE ... VALUE COMPRESSION

要更改某个现有的表使用的行格式,可发出以下语句之一:

  ALTER TABLE ... ACTIVATE VALUE COMPRESSION
  
  ALTER TABLE ... DEACTIVATE VALUE COMPRESSION

如果激活或取消激活某个表的值压缩,那么不会修改表中存储的现有数据。相反,各行会保留它们当前的行格式,除非应用本文的 采用战略 一节中提供的一个或多个度量。

对于使用备用行格式的表,可通过为固定长度的数值和字符列启用默认值压缩来节省更多空间。这会导致系统默认值(0 表示数值列,空白表示固定长度字符列)不会物化到一行的磁盘表示中。可通过在 CREATE TABLEALTER TABLE ... ALTER COLUMN SQL 语句中为某个列指定 COMPRESS SYSTEM DEFAULT 列选项,为该列单独启用系统默认值压缩。

确定使用哪种格式

尽管标准行格式在大部分情况下都是一个不错的选择,但对某些表而言,备用行格式可能会带来更紧凑的存储布局:

  • 稀疏填充的表(即众多行都包含许多 NULL 或系统默认值的表)应该使用备用行格式。但是,只要将 NULL 或系统默认值更新为 NULL 或系统默认值以外的值,一行的存储空间需求就会增加。这一更改通常会导致溢出记录的发生,甚至在没有可变长度的列的表(即在使用标准行格式时所有行都具有相同的空间需求的表)中也是如此。
  • 绝大部分的列都具有可变长度数据类型的表应该使用备用行格式。

对于一些没有这些特征的表,使用备用行格式可能会增加存储空间需求。因此您可能有必要在自己的环境中测试一下。

无论您是否拥有 DB2 Storage Optimization Feature 许可,都可以使用备用行格式。这一灵活性支持您为每个表选择最紧凑的存储布局,即使您未计划使用行压缩。但是,如果计划使用行压缩,在大多数情况下,从一开始就选择最紧凑的行格式都会让表占用更小的磁盘空间,不过这一效果并没有那么显著,或者甚至无法察觉。这源于这样一个事实:行压缩可以很好地压缩具有标准行格式的表中物化的 NULL 和系统默认值。


行压缩

行压缩是在 DB2 9 for Linux, UNIX, and Windows 中引入的,在自那以后的每个版本中都对它的功能进行了重大改进,这些改进累积形成了 DB2 10.1 中提供的下一代自适应压缩功能。行压缩需要一个 DB2 Storage Optimization Feature 许可。

从 DB2 10.1 开始,有两种类型的行压缩方法可供使用:

  • 经典行压缩 指的是已用于以下数据的压缩技术:
    • 用户表数据,自 DB2 9 for Linux, UNIX, and Windows 推出后
    • XML 和临时数据,自 DB2 9.7 for Linux, UNIX, and Windows 推出后
  • 自适应行压缩 是 DB2 10.1 中引入的一种可应用于用户表数据的新压缩模式。自适应行压缩比经典行压缩更优秀,因为它一般会实现更高的压缩率,需要更少的数据库维护工作即可保持接近最佳水平的压缩率。

经典行压缩

经典行压缩依赖于一种基于字典的压缩算法。每个表对象都有一个压缩字典。该字典包含整个表中的行中经常发生的模式映射。此压缩字典称为表级压缩字典。经典行压缩的工作原理的示例如图 1 所示。

图 1. 经典行压缩的工作原理
该图显示了如何使用一个表级压缩字典来存储某个表,从而减少重复模式

可以为每个表启用行压缩。要执行经典行压缩,则必须为该表启用压缩,并且必须存在一个针对该数据或 XML 对象的字典。要在创建表时在 DB2 10.1 对某个表启用经典行压缩,可以执行 CREATE TABLE ... COMPRESS YES STATIC 语句。

另一方面,要对一个现有的表启用经典行压缩,可以执行 ALTER TABLE 语句,该语句类似于 ALTER TABLE ... COMPRESS YES STATIC

在 DB2 10.1 中,COMPRESS YES 子句中的 STATIC 选项在两种情况下都是强制性的。在早期的 DB2 版本中,可以无需任何修改地使用 COMPRESS YES 子句,如下所示:

  CREATE TABLE ... COMPRESS YES
  
  ALTER TABLE ... COMPRESS YES

对绝大部分实际的表而言,启用行压缩会节省空间;压缩率通常为 50-80% 或更高。而且,使用行压缩的表的存储空间占用绝不会超过相同表的未压缩版本。

因为相同数量的行可以存储在更少的物理页面上,所以行压缩带来的存储空间节省通常会转化为读取压缩的表中的数据所需的更少的物理 I/O 操作。(压缩允许将更多数据行放入相同数量的页面中,而且缓冲池命中率也提高了。)在许多情况下,I/O 节省和改进的缓冲池利用率会带来更高的吞吐量和更快的查询执行时间。

自适应行压缩

像经典行压缩一样,自适应行压缩依赖于一种基于字典的压缩算法。区别在于每个表对象可以有多个压缩字典。每个字典包含一个页面中的各行中经常出现的模式映射。所以,这些压缩字典称为页级压缩字典。图 2 显示了自适应行压缩的工作原理的一个示例。自适应压缩不仅会在许多情况下带来高得多的压缩率,还能够适应不断变化的数据特征。

图 2. 自适应行压缩的工作原理
该图显示了页级压缩字典

与经典行压缩一样,可以对每个表启用自适应行压缩。在 DB2 10.1 中,要创建一个启用了自适应行压缩的表,只需执行以下语句之一:

  CREATE TABLE ... COMPRESS YES ADAPTIVE
  
  CREATE TABLE ... COMPRESS YES

另一方面,要对现有的表启用自适应行压缩,可以执行一条 ALTER TABLE 语句,该语句类似于以下语句:

  ALTER TABLE ... COMPRESS YES ADAPTIVE
  
  ALTER TABLE ... COMPRESS YES

在 DB2 10.1 中,自适应行压缩是使用的默认的行压缩类型。因此,ADAPTIVE 选项是 COMPRESS YES 子句的默认值。

当从一个较早的 DB2 for Linux, UNIX, and Windows 版本升级数据库时,启用了经典行压缩的现有表会保留其压缩设置并使用经典行压缩。因此,如果希望对这些表启用自适应行压缩,必须使用前面给出的 ALTER TABLE 语句之一。

如上所述,自适应行压缩构建于经典行压缩之上;仍然使用表级压缩字典。表级字典由页级压缩字典提供补充,后者包含针对某个页面中经常发生的模式的条目。表级字典有助于消除全局范围内的重复模式,而页级字典负责消除在各个页面上找到的本地重复模式。图 3 中演示了表级和页级字典的这一组合的使用方式。

图 3. 使用自适应压缩时的表级和页级压缩字典的协同工作方式
该图显示了两种压缩字典类型在全局范围内的结合使用

页级字典会自动进行维护。当在一个页面中填入数据后,DB2 数据库管理器会为该页中的数据创建一个页级压缩字典。随着时间的推移,DB2 数据库管理器会自动确定何时为数据模式发生重大变化的页面重新创建该字典。这样,自适应压缩的使用不仅会带来更高的总体压缩节省,还可确保压缩率随时间流逝而降低的幅度没有经典行压缩那么大。在许多实际情形中,压缩率总是保持接近最佳状态。因此,通过使用自适应行压缩,您可以减少与监视表的压缩率和执行必要的维护(经典和离线表重组)相关的成本,改善存储利用率。


揭示压缩设置

通过检查 SYSCAT.TABLES 系统目录视图中的 COMPRESSION 列,可以确定某个表是否启用了行压缩以及它使用了哪种行格式。此列可能的值如下所示:

  • V 表示使用了备用行格式,没有行压缩
  • R 表示使用了行压缩和标准行格式
  • B 表示使用了备用行格式和行压缩
  • N 表示没有使用行压缩,但使用了标准行格式

在 DB2 10.1 中,您可以通过检查 SYSCAT.TABLES 系统目录视图中的 ROWCOMPMODE 列,确定表上使用了哪种行压缩类型。此列可能的值如下:

  • S 表示使用了经典行压缩
  • A 表示使用了自适应行压缩
  • 留空 表示未启用行压缩

SYSCAT.TABLES 系统目录视图的 ROWCOMPMODE 列在早期的 DB2 版本中不存在。在此情况下,所有启用了行压缩的表都会隐式地使用经典行压缩。

如果安装了 DB2 10.1 for Linux, UNIX, and Windows,那么可以使用以下查询获取已定义的所有用户表的压缩设置。

清单 1. 使用查询获取压缩设置
  SELECT SUBSTR(TABSCHEMA, 1, 10) AS TABSCHEMA,
         SUBSTR(TABNAME, 1, 10) AS TABNAME,
         COMPRESSION, ROWCOMPMODE
  FROM SYSCAT.TABLES
  WHERE TABSCHEMA NOT LIKE 'SYS%'

在执行此查询时,应当会看到类似清单 2 的结果。

清单 2. 查询结果显示了压缩设置
  Sample results are as follows:
  TABSCHEMA  TABNAME    COMPRESSION ROWCOMPMODE
  ---------- ---------- ----------- -----------
  DB2INST1   ACCTCR     R           S
  DB2INST1   BKPF       R           A
  DB2INST1   BSIS       B           A
  DB2INST1   CDCLS      N
  DB2INST1   CDHDR      V
  DB2INST1   COSP       B           S

    6 record(s) selected.

在此示例中,ACCTCR、BKPF、BSIS 和 COSP 表都启用了行压缩。ACCTCR 和 COSP 表使用了经典行压缩,BKPF 和 BSIS 表使用自适应行压缩。BSIS 和 COSP 表也使用备用行格式,但 ACCTCR 和 BKPF 表使用标准行格式。CDHDR 表使用没有行压缩的备用行格式,CDCLS 表使用没有行压缩的标准行格式。


构建一个压缩字典

在经典行压缩在启用了压缩的表中生效之前,必须有一个针对该表的字典。在 DB2 9 中,必须注意是否存在压缩字典,如果有必要,则必须创建一个表级字典。可通过执行一个离线(经典)表重组操作 来创建表级压缩字典(并压缩表中的现有数据)。这个操作可通过执行指定了 KEEPDICTIONARYRESETDICTIONARY 选项的 REORG 命令来执行。如果执行指定了上面的某个选项的 REORG 命令,并且不存在压缩字典,那么系统会创建一个新字典。另一方面,如果执行指定了某个选项的 REORG 命令,并且已经存在一个压缩字典,则会重新创建现有的字典 (RESETDICTIONARY) 或保持不变 (KEEPDICTIONARY),表中的数据将被重组或压缩。

要为一个启用了深度压缩的名为 EMPLOYEE 的表创建一个新压缩字典(并重组和压缩该表的数据),可以执行以下命令:

  REORG TABLE employee RESETDICTIONARY

执行此命令时,将分析存储在 EMPLOYEE 表中的数据,在表的开头部分构造并存储一个压缩字典,这会将所有现有的数据压缩并写到表中紧挨压缩字典之后的位置。图 4 展示了在应用深度压缩之前和之后的 EMPLOYEE 表的外观。

图 4. 构建一个压缩字典并应用经典行压缩时某个表中的数据的修改情况
该图显示了写入表中的压缩数据

一定要注意的是,因为压缩的表中的记录以压缩格式在存储区和内存之间迁移,所以写入事务日志文件的压缩表的记录也是压缩的。(压缩字典会在访问表时加载到内存中,这样才能执行压缩和解压。)


自动字典创建 (ADC)

您可能已想到,只有根据包含所有数据的集合构建压缩字典时,才能实现最佳的压缩率。因此,当通过重组某个表来构建压缩字典时,会得到较高的压缩率,因为使用了表中的所有行。但是,测试表明,在仅分析少量代表性的数据时,也有可能得到较好的压缩率。(在某些情况下,对不到总行数的 1% 的数据进行计算可得到 45% 的压缩率。)这一概念形成了 DB2 9.5 中添加的称为自动字典创建 (Automatic Dictionary Creation, ADC) 的压缩特性的基础。

在 DB2 9.5 及其更高版本中,如果在创建表时启用了压缩,ADC 会导致在表中存储足够多的数据时自动构建一个压缩字典。触发 ADC 开始构造压缩字典的阈值取决于表的行大小。字典构造通常从向表分配了 1-2 MB 的页面开始。在这时,ADC 会检查表中包含多少用户数据;如果至少有 700 KB 数据,则会构建一个压缩字典。(请注意,这些值是在内部设置的,无法更改。)可触发 ADC 的操作包括在各个分区插入、导入、加载和重新分配数据。

不同于 REORG 操作构建的压缩字典,以 ADC 的方式创建的字典存储在表中现有数据的末尾处。在执行离线表重组操作之前或更新已存在的记录之前(在这种情况下,保存更改时会压缩修改的每条记录),表中现有的记录会保持未压缩状态。新纪录会在添加时进行压缩。(ADC 的一个目标是构建这样一个压缩字典:该字典会带来合理的压缩率,但又不会在表中留下大量未压缩的数据。)图 5 显示了一个在创建时启用了压缩的表在 ADC 构建压缩之前之前、期间和之后的外观。

图 5. ADC 的工作原理
该图显示了创建表、插入数据、构建字典的过程,然后该表即包含表级压缩字典以及表级和页级压缩数据

当为一个填充的表启用压缩时(通过将 COMPRESS 属性设置为 ON),不会自动创建一个压缩字典。在下一次发生表增长操作时,会触发 ADC,并会使用表的开头部分的少量记录为整个表构建一个压缩字典。创建字典后,会压缩后续的插入、导入、加载和重新分配操作向表添加的数据;已存在的数据保持未压缩状态。

可以看到,压缩字典的自动创建在一定程度上受表的压缩属性控制。为了避免 ADC 行为,在准备好手动构建压缩字典并压缩数据之前,不要对表启用压缩。另一方面,如果选择利用 ADC,请记住,字典生成的压缩率可能没有离线表重组所创建的字典那么高。另外,因为表会在构建压缩字典时保持在线状态,所以在超过阈值并触发 ADC 时,导致 ADC 触发的事务会给性能带来少许负面影响。

一定要注意的是,随着时间的推移,与使用经典表重组构建的字典相比,使用 ADC 构建的字典带来的存储空间节省可能更少。另外,随着时间的推移,包含频繁更新的数据表的表级字典可能不再包含不断更改的数据的最有效模式,从而导致压缩率下降。在这些情况下,可能需要执行定期经典表重组来维持一致的高存储空间节省。


识别可执行行压缩的候选表

如果还未使用行压缩,您可能希望检查数据库来确定哪些表可从数据压缩中获益。因为数据压缩有助于节省现有的未压缩表上的存储空间,优化未来的存储增长,所以您可通过检查包含大量数据的表或您预计会显著增长的表,找出存储难点。

自然地,最大的表是明显的压缩候选者,但不要忽略较小的表。如果有数百个或数千个小表,您可能会从压缩的聚合效应中获益。当然,“大” 和 “小” 是相对的概念;您的数据库设计决定了包含几百万行的表应被视为大表还是小表。

以下查询使用 SQL 管理函数 ADMIN_GET_TAB_INFO() 返回具有特定模式的所有表名称和表数据对象大小的有序列表。为了显示当前使用的压缩设置和行压缩模式,生成的结果集已与 SYSCAT.TABLES 视图联接,返回了 COMPRESSIONROWCOMPMODE 列中的数据。

清单 3. 查找可压缩的候选表的查询
  SELECT SUBSTR(T.TABSCHEMA, 1, 10) AS TABSCHEMA,
         SUBSTR(T.TABNAME, 1, 10) AS TABNAME,
         SUM(TI.DATA_OBJECT_P_SIZE)/1024/1024 AS STORAGESIZE_GB,
         T.COMPRESSION AS COMPRESSION,
         T.ROWCOMPMODE AS ROWCOMPMODE
  FROM TABLE (SYSPROC.ADMIN_GET_TAB_INFO('DB2INST1', '')) TI
         JOIN SYSCAT.TABLES T ON T.TABSCHEMA = TI.TABSCHEMA AND
                                 T.TABNAME = TI.TABNAME
  GROUP BY T.TABSCHEMA, T.TABNAME, T.COMPRESSION, T.ROWCOMPMODE
  ORDER BY STORAGESIZE_GB DESC

此查询识别当前的数据库中使用空间最多的表,并提供一组应处理的候选表。在许多实际场景中,一个数据库的大量存储空间被少数的表占用。

基于存储使用情况确定了候选表之后,可以考虑对以下表中的数据执行典型的 SQL 活动:

  • 只读表是行压缩的最佳候选者。读操作占 70% 或更高比例而写操作占 30% 或更低比例的表是行压缩的不错候选者。
  • 仅执行有限数量的更新的表可能是行压缩的不错候选者。
  • 经历大量更新的表可能不是行压缩的良好候选者。
  • 最常通过表扫描而不是索引扫描访问的大型表是压缩的不错候选者。这一般包括数据仓库中的大型事实表,其中大量的查询会执行大量聚合操作。应用压缩所带来的 I/O 节省和更高的缓冲池利用率可能改善这些表的查询性能。

最好使用经典行压缩还是自适应行压缩,这主要取决于您可通过使用每种压缩获得的实际压缩节省,其次取决于数据访问模式。您可在以后决定选择哪种行压缩模式。

在工作负载不会受到 CPU 限制的 I/O 或内存受限的环境中,行压缩性能最高。在访问或修改数据行时,需要额外的 CPU 周期来执行数据行的行压缩和扩展。此开销可由执行更少的 I/O 操作上带来的效率提升进行补偿。行压缩非常适合包含执行大量聚合的复杂分析查询的决策支持工作负载,在这些工作负载中,行访问主要是顺序的,不是随机的。


计算使用行压缩带来的存储节省

创建一个压缩候选表列表后,基于存储使用情况和数据访问特征,下一步是确定您预计压缩这些表后可实现的存储空间节省。可以在启用行压缩之前计算任何表的空间节省。而且,即使没有 DB2 Storage Optimization Feature 许可,也可以计算存储空间节省。

与一般的压缩功能一样,压缩计算的机制在不断发展,其主要目标是提供更快且更简单的方式来执行此任务。所选的机制依赖于您使用的 DB2 软件版本。旧版本中提供的所有工具和功能也包含在 DB2 10.1 中。但是,您可能发现,DB2 10.1 中改进的功能更容易使用或能够更快地提供您寻找的数据。

计算 DB2 10.1 中的行压缩节省

在 DB2 10.1 中,计算压缩率的首选方式是使用 ADMIN_GET_TAB_COMPRESS_INFO() 管理函数。可使用此函数计算特定表的压缩节省,计算一种特定模式中所有表的压缩节省,或者计算一个数据库中所有表的压缩节省。此外,此函数还可计算经典和自适应行压缩的当前压缩节省和节省预测。

ADMIN_GET_TAB_COMPRESS_INFO() 表函数的语法是 ADMIN_GET_TAB_COMPRESS_INFO (TableSchema, TableName),其中:

  • TableSchema 通过名称来识别要获取其压缩信息的表所属的模式。(如果此参数包含一个空值或 NULL 值,则使用所有模式。)
  • TableName 通过名称来识别要获取其压缩信息的表。(如果此参数包含空值或 NULL 值,则使用所有表名称。)

如果未指定表名称,那么该函数会计算特性模式中所有表的节省值;如果未指定表名称或模式,那么它会计算一个数据库中的所有表。(如果您的模式或数据库包含数百个或数千个表,处理时间可能会很长;在这种情况下,可尝试将查询限制为仅计算您考虑压缩的表的节省值。)

ADMIN_GET_TAB_COMPRESS_INFO() 函数返回的表的结构如表 1 中所示。

表 1. ADMIN_GET_TAB_COMPRESS_INFO() 函数返回的表
列名称数据类型描述
TABSCHEMAVARCHAR(128)模式名称
TABNAMEVARCHAR(128)表名称
DBPARTITIONNUMSMALLINT数据库分区编号
OBJECT_TYPEVARCHAR(4)报告其压缩信息的对象的类型,它可以是以下值之一:
  • 'XML' = 报告 XML 数据的压缩信息
  • 'DATA' = 报告关系数据的压缩信息
ROWCOMPMODECHAR(1)对象当前的行压缩模式,它可是以下值之一:
  • 'S' = 启用经典行压缩
  • 'A' = 启用自适应行压缩
  • 留空 = 未启用行压缩
PCTPAGESSAVED_CURRENTSMALLINT当前从行压缩节省的页数百分比
AVGROWSIZE_CURRENTSMALLINT当前的平均记录长度
PCTPAGESSAVED_STATICSMALLINT计算的从经典行压缩节省的页数百分比
AVGROWSIZE_STATICSMALLINT计算的经典行压缩得到的平均记录长度
PCTPAGESSAVED_ADAPTIVESMALLINT计算的从自适应行压缩节省页数百分比
AVGROWSIZE_ADAPTIVESMALLINT计算的自适应行压缩得到的平均记录长度

因此,如果您希望获得压缩一个名为 DB2INST1 的模式中每个表中的数据将节省的存储空间值,可执行一个类似清单 4 的查询。

清单 4. 计算存储节省的查询
  SELECT SUBSTR(TABNAME,1,10) AS TABNAME,
                PCTPAGESSAVED_CURRENT,
                PCTPAGESSAVED_STATIC,
                PCTPAGESSAVED_ADAPTIVE
    FROM TABLE(SYSPROC.ADMIN_GET_TAB_COMPRESS_INFO('DB2INST1', ''))

使用此查询的结果,您可轻松地确定是否对某个特定的表启用行压缩和应该使用何种行压缩模式,例如,上一个查询是否返回了类似清单 5 的结果集。

清单 5. 示例结果
  TABNAME    PCTPAGESSAVED_CURRENT PCTPAGESSAVED_STATIC PCTPAGESSAVED_ADAPTIVE
  ---------- --------------------- -------------------- ----------------------
  ACCTCR                         0                   68                     72
  BKPF                           0                   83                     90
  BSIS                           0                   82                     90
  CDCLS                          0                   11                     17
  CDHDR                          0                   70                     73
  COSP                           0                   87                     91

    6 record(s) selected.

在 6 个计算了压缩节省值的表中,5 个表现出了非常好的压缩潜力。CDCLS 表是惟一无法从压缩获益的表。在任何情况下,似乎自适应行压缩都会得到比经典行压缩更好的结果。

计算 PCTPAGESSAVED_STATIC 和 PCTPAGESSAVED_ADAPTIVE 列的值之间的区别,可帮助您确定最佳的行压缩模式选择。但是,请注意 PCTPAGESSAVED_CURRENT 列的值的比例不是线性的。例如,考虑上一个示例中给出的 ACCTCR 和 COSP 表。对于 ACCTCR 表,可以预计使用经典行压缩节省 68% 的空间,使用自适应行压缩节省 72% 的空间。对于 COSP 表,计算的节省为经典行压缩 87%,自适应行压缩 91%。尽管对于每个表,两种类型之间的绝对差为 4%,但自适应行压缩相对于经典行压缩的相对节省是不同的。假设在未启用压缩时,每个表的大小为 100 GB。对于 ACCTCR 表,计算的大小为经典行压缩 32 GB 和自适应行压缩 28 GB,它们之间存在大约 12.5% 的差距。但是,对于 COSP 表,计算的大小为经典行压缩 13 GB,自适应行压缩 9 GB,它们之间的差距大约为 30%。

在上一个示例中,COSP 表是自适应压缩的好的候选者,而 ACCTCR 表可能不是好的候选者。而且,计算的值表明,相比经典行压缩,自适应压缩只能将 CDHDR 表的存储大小减少另外 10%。结果,您可能不希望为 CDHDR 和 ACCTCR 启用自适应压缩,除非您预计数据特征会显著更改或者您预计将插入大量新数据。对于剩余表,自适应压缩可能是更好的选择,因为它能带来高达 45% 的额外的存储空间节省。

计算 DB2 9.7 和 9.5 中的行压缩节省

在 DB2 9.7 和 9.5 中,可以使用与 DB2 10.1 提供的 ADMIN_GET_TAB_COMPRESS_INFO() 函数非常类似的管理函数,但它们的名称和签名稍有不同。在 DB2 9.7 中,该函数名为 ADMIN_GET_TAB_COMPRESS_INFO_V97();而在 DB2 9.5 中,它的名称为 ADMIN_GET_TAB_COMPRESS_INFO()。与接受两个输入参数的 DB2 10.1 函数不同,DB2 9.5 和 9.7 函数接受了 3 个参数。第三个参数是执行模式,对于压缩计算,传递字符串 'ESTIMATE' 作为此参数的值。DB2 9.5 和 9.7 函数返回的表的结构与 DB2 10.1 函数生成的表的结构有很大差别;DB2 9.5 和 9.7 函数返回的表结构如表 2 中所示。

表 2. DB2 9.5 和 9.7 函数返回的表
列名称数据类型描述
TABSCHEMAVARCHAR(128)模式名称
TABNAMEVARCHAR(128)表名称
DBPARTITIONNUMSMALLINT数据库分区编号
DATA_PARTITION_IDINTEGER数据分区编号
COMPRESS_ATTRCHAR(1)表上的 COMPRESS 属性的状态,它可是以下值之一:
  • 'Y' = 行压缩设置为 YES
  • 'N' = 行压缩设置为 NO
DICT_BUILDERVARCHAR(30)对于用来构建压缩字典的代码路径,它可是以下值之一:
  • 'NOT BUILT' = 没有字典可用
  • 'INSPECT' = INSPECT ROWCOMPESTIMATE
  • 'LOAD' = LOAD INSERT/REPLACE
  • 'REDISTRIBUTE' = REDISTRIBUTE
  • 'REORG' = REORG RESETDICTIONARY
  • 'TABLE GROWTH' = INSERT, IMPORT(使用了 INSERT)或大小增加更新,后者会导致 DB2 将更新的记录放在一个新页上
DICT_BUILD_TIMESTAMPTIMESTAMP创建压缩字典的日期和时间;如果没有字典可用,则时间戳为 NULL
COMPRESS_DICT_SIZEBIGINT压缩字典的大小,以字节为单位
EXPAND_DICT_SIZEBIGINT扩展字典的大小,以字节为单位
ROWS_SAMPLEDINTEGER用于构建字典的记录数;具有压缩字典的迁移的表将在此列中返回 NULL
PAGES_SAVED_PERCENTSMALLINT压缩所节省的页数百分比。此信息仅基于抽样缓冲区中的记录数据。具有压缩字典的迁移的表将在此列中返回 NULL。
BYTES_SAVED_PERCENTSMALLINT压缩所节省的字节数百分比。此信息仅基于抽样缓冲区中的记录数据。具有压缩字典的迁移的表将在此列中返回 NULL。
AVG_COMPRESS_REC_LENGTHSMALLINT用于构建字典的记录的平均压缩记录长度。具有压缩字典的迁移的表将在此列中返回 NULL。

而且,管理函数的处理时间可能比 DB2 10.1 中长得多,因为会为每个表执行全表扫描来计算压缩节省。

计算 DB2 9 中的行压缩节省

DB2 9(第一个支持行压缩的 DB2 版本)没有提供在以后的版本中引入的任何管理函数。但是,如果使用此版本,仍然可以确定哪些表可从行压缩获得最大收益,只需使用 Inspect 实用程序即可。Inspect 实用程序可通过执行指定了 ROWCOMPESTIMATE 选项的 INSPECT 命令来调用,它将检查某个特定表中的每一行,根据找到的数据构建一个压缩字典,然后使用此字典计算压缩该表中的数据会节省多少空间。

例如,要计算压缩一个名为 EMPLOYEE 的表中的数据会节省多少空间,可以执行 INSPECT 命令,该命令类似于以下命令:

  INSPECT ROWCOMPESTIMATE TABLE NAME employee RESULTS employee.rowcompestimate.out

运行指定了 RESULTS 选项的这个命令,这会导致 Inspect 实用程序将生成的输出保存在诊断数据目录中的某个文件中。但是,在查看此文件中存储的信息之前,必须使用 db2inspf: db2inspf employee.rowcompestimate.out employee.rowcompestimate.txt 将其格式化。

生成的格式化文件将包含有关计算的压缩节省的信息,这些信息类似于清单 6。

清单 6. 计算行压缩节省
  DATABASE: TEST
  VERSION : SQL10010
  2011-11-07-18.39.23.555355

  Action: ROWCOMPESTIMATE TABLE
  Schema name: DB2INST1
  Table name: EMPLOYEE
  Tablespace ID: 4  Object ID: 8
  Result file name: employee.rowcompestimate.out

      Table phase start [...]
  
        Data phase start. Object: 8  Tablespace: 4
        Row compression estimate results:
        Percentage of pages saved from compression: 68
        Percentage of bytes saved from compression: 68
        Compression dictionary size: 32640 bytes.
        Expansion dictionary size: 32768 bytes.
        Data phase end.
      Table phase end.
  Processing has completed. 2011-11-07-18.40.08.349345

如果在执行 INSPECT 命令之前对某个表启用了深度压缩(也就是说将 COMPRESS 属性设置为 YES),构建并用于计算空间节省的压缩字典将会写入该表中,放在现有数据的末尾,前提是之前不存在压缩字典。(否则,创建的压缩字典将被销毁。)图 6 显示了如果在获取计算结果之前启用了深度压缩,使用 Inspect 实用程序计算存储节省之前和之后的表。

图 6. 当 Inspect 实用程序计算启用了深度压缩的表时,该表中的数据的修改情况
该图显示了在运行 Inspect 实用程序后,会添加一个表级压缩字典

无论使用何种方法来创建它,在创建一个压缩字典并将其写入一个表后,都会自动压缩添加到该表的新纪录。如果压缩字典是 Inspect 实用程序创建的,那么在执行离线表重组操作或更新已存在的记录(在此情况下,每个修改的记录都会压缩)之前,表中已存在的记录会保持未压缩状态。

在后来的 DB2 版本中,不应使用 Inspect 实用程序来构建表级字典,而应依靠 ADC。


索引压缩

如果使用的是 DB2 9.7 或其更高版本,并且拥有 DB2 Storage Optimization Feature 许可,则可以对索引使用压缩。压缩索引会得到更少的叶页面,这在许多情况下有助于减少索引树的深度。压缩索引使得访问更少的索引页即可找到特定的键,并且就像行压缩一样,可以提高缓冲池的利用率并且需要更少的物理 I/O 操作。在许多实际情况下,索引压缩可显著提高查询性能。

可单独对每个索引启用索引压缩。在创建索引时,该索引会从基础表继承它的压缩设置。也就是说,您在启用了经典或自适应行压缩的表上创建的所有索引也都是经过压缩的。因此,您可能会发现,如果创建启用了压缩的表,或在表上创建任何索引之前修改它们来启用行压缩,这样做很有用。

索引压缩结合使用 3 种技术来减少磁盘上存储的数据量。空间节省是通过动态调整索引键数量来实现的,而不是通过将空间保留给可在一个页面中存储的最多的键来实现。索引条目(每个条目有一个索引键和一个 RID 列表组成)通过消除一个页面中的键中的冗余前缀来实现压缩。对于重复的键,每个列表中关联的 RID 通过应用 delta 编码来进行压缩。

与自适应行压缩类似、但不同于经典行压缩的是,索引压缩是全自动的。索引压缩始终会保持最佳的压缩节省,并且无需监视和潜在地重组索引来改进压缩率。


识别可执行索引压缩的候选索引

最佳的压缩候选者是具有长键的索引(例如多列索引或字符数据上的索引)和包含许多重复键的索引(例如,基于单个或有限数量的低基数列的索引)。此外,涉及可变长度列(例如 VARCHAR 列)的索引可获得动态索引页面空间管理所提供的更高的空间利用率。

如果前导的键列具有低到中等的基数,以及更高的基数或惟一的列可能靠近键列列表末尾,多列索引一般会得到更高的压缩率。根据您期望索引支持的查询的特征,有可能在不牺牲查询性能的前提下进行列重新排序。也可能有必要检查更大的索引的列的顺序和基数,尤其是在数据仓库场景中。在这些情况下,大部分查询都会聚合更大量的有资格的行上的值,并且查询特征一般比 OLTP 工作负载更可预测。

可能从压缩中获得较少收益的索引示例包括单个惟一的数字列上的索引,或者将最高基数的列用作前导索引列的惟一的多列索引。


计算索引压缩的存储空间节省

当决定压缩哪些索引时,存储空间节省的计算所发挥的作用比压缩表时更大。与索引压缩关联的计算开销比行压缩更小,存储空间节省一般会更直接地带来总体性能改进。如果您可为 OLTP 工作负载中的任何索引实现重大的空间节省,压缩它们是一个不错的想法。

类似于 ADMIN_GET_TAB_COMPRESS_INFO() 函数,ADMIN_GET_INDEX_COMPRESS_INFO() 可用于计算索引压缩的存储空间节省。此函数可用于计算单个索引、特定表上的所有索引、特定模式中的所有所有索引或一个数据库中的所有索引的压缩节省;执行模式由前三个输入参数控制。ADMIN_GET_INDEX_COMPRESS_INFO() 表函数的语法如下:

ADMIN_GET_INDEX_COMPRESS_INFO (ObjectType, ObjectSchema, ObjectName, Member, DataPartitionID)

其中:

  • ObjectType 识别要获得其压缩节省信息的对象类型。必须为此参数分配以下区分大小写的值之一:
    • 'T'、NULL 或表示一个表的空字符串
    • 'I' 表示一个索引
  • ObjectSchema 按名称来识别对象属于哪个模式。
  • ObjectName 按名称识别要获得哪个对象的压缩信息。
  • Member 识别一个数据库成员编号。(当为此参数提供一个值时,只会返回位于指定的数据库成员之上的索引的信息。)
  • DataPartitionID 识别数据分区 ID。(当为此参数提供一个值时,只会返回已在指定的数据分区上定义的索引分区的信息。)

如果希望计算单个索引或特定模式中的所有索引的空间节省,可指定对象类型 'I'。要计算某个特定表上或某个模式或数据库中的所有表上的所有索引的空间节省,可指定对象类型 'T'、NULL 或空字符串。根据对象类型参数的值,可以使用对象名称和对象模式参数来识别要分析的表或索引。也可以将对象名称和对象模式参数的值保留为 NULL 或空字符串,从而计算一个索引范围的压缩节省。

ADMIN_GET_INDEX_COMPRESS_INFO() 函数返回的表的结构如表 3 中所示。

表 3. ADMIN_GET_INDEX_COMPRESS_INFO() 函数返回的表
列名称数据类型描述
INDSCHEMAVARCHAR(128)索引模式名称
INDNAMEVARCHAR(128)索引名称
TABSCHEMAVARCHAR(128)表模式名称
TABNAMEVARCHAR(128)表名称
DBPARTITIONNUMSMALLINT数据库分区编号
IIDINTEGER索引标识符
DATAPARTITIONIDINTEGER数据分区 ID
COMPRESS_ATTRCHAR(1)索引上的 COMPRESSION 属性的状态,它可是以下值之一:
  • 'Y' = 索引压缩设置为 YES
  • 'N' = 索引压缩设置为 NO
INDEX_COMPRESSEDCHAR(1)物理索引格式,它可是以下值之一:
  • 'Y' = 索引为压缩格式
  • 'N' = 索引为未压缩格式
如果物理索引格式与压缩属性不匹配,则需要执行一次索引重组,将索引转换为定义的格式。如果在执行此函数时表或索引存在错误,此值为 NULL。
PCT_PAGES_SAVEDSMALLINT压缩所节省的页数百分比。如果索引未进行物理压缩(INDEX_COMPRESSED 为 “N”),此值表示计算的节省的叶页数百分比,就像实际压缩索引一样。如果对索引进行了物理压缩(INDEX_COMPRESSED 为 “Y”),此值会报告来自系统目录视图的(SYSCAT.INDEXES 或 SYSCAT.INDEXPARTITIONS)的 PCTPAGESSAVED 值。
NUM_LEAF_PAGES_SAVEDSMALLINT节省的叶页数。如果未对索引进行物理压缩(INDEX_COMPRESSED 为 “N”),此值表示计算的节省的叶页数百分比,就像实际压缩索引一样。如果索引进行了物理压缩(INDEX_COMPRESSED 为 “Y”),此值报告来自系统目录视图的(SYSCAT.INDEXES 或 SYSCAT.INDEXPARTITIONS)的 PCTPAGESSAVED 和 NLEAF 值。如果 PCTPAGESSAVED 或 NLEAF 是无效的值 (-1),此值也设置为 -1。

因此,如果希望获得压缩一个名为 EMPLOYEE 的表(位于模式 DB2INST1 中)上的每个索引时,将节省的存储空间的计算结果,可通过执行一个类似清单 7 的查询来完成此操作。

清单 7. 获取索引压缩的示例查询
  SELECT SUBSTR(INDNAME, 1, 20) AS INDNAME,
         COMPRESS_ATTR,
         PCT_PAGES_SAVED
    FROM TABLE(SYSPROC.ADMIN_GET_INDEX_COMPRESS_INFO('T', 'DB2INST1', 'EMPLOYEE', 
                                                     NULL, NULL))

使用此查询的结果,可以轻松地确定是否对某个特定索引启用压缩。例如,如果上面的查询返回一个类似清单 8 的结果集:

清单 8. 索引压缩的查询结果
INDNAME              COMPRESS_ATTR PCT_PAGES_SAVED
-------------------- ------------- ---------------
EMPLOYEE~0           N                          46
EMPLOYEE~1           N                          57
EMPLOYEE~2           N                          71
EMPLOYEE~3           N                          71
EMPLOYEE~4           N                          45
EMPLOYEE~5           N                          71
EMPLOYEE~6           N                          70
EMPLOYEE~BUT         N                          71

  8 record(s) selected.

您会很容易地看到,EMPLOYEE 表上的大部分索引得到了很好的压缩,节省了高达 70% 的存储空间。

如果使用 ADMIN_GET_INDEX_COMPRESS_INFO() 函数分析已压缩的索引,返回的压缩节省会反映收集的实际节省,而不是计算值。也可以获取索引压缩当前实现的节省,只需检查 SYSCAT.TABLES 目录视图的 PCTPAGESSAVED 列。(RUNSTATS 命令维护此列的值。)


临时表的压缩

从 DB2 9.7 开始,如果有一个 DB2 Storage Optimization Feature 许可,则可以向临时表应用压缩。与行和索引压缩不同,您无需对临时表启用压缩。压缩是自动完成的,适用于用户定义的临时表和系统临时表。(用户定义的全局临时表有两种变形:已创建的全局临时表 (CGTT) 和已声明的全局临时表 (DGTT)。系统临时表供一些实用程序和维护操作使用,比如表重组和数据重新分配。在查询处理期间,DB2 数据库管理器也可以创建和使用临时表来执行一些必须累积中间结果的操作,比如排序、哈希联接或表查询。

用于压缩临时表的机制与用于具有 ADC 的经典行压缩的机制相同,但运行时行为与永久表稍有不同。大部分临时表(尤其是小临时表)都不会导致任何物理 I/O。因此,构建的压缩字典的上限为 100 MB,而不是 2 MB。更高的上限可确保通常完全保留在缓冲区的小临时表不会被压缩,但可能溢出到磁盘的更大的临时表会包含压缩数据。除了避免物理 I/O,临时表的压缩可确保较大的临时表更高效地使用缓冲池,这有助于进一步避免物理磁盘 I/O。


采用战略

在确定压缩哪个表和索引集合之后,下一步就是对这些表和索引启用压缩。更改已填充的现有表的压缩设置有助于减缓它们的增长速率,插入的数据会从新的压缩设置中获益。如果您的目标是减少现有数据的空间占用(或许因为您希望减少数据库使用的物理空间),您必须向此数据应用压缩。

您可以使用以下战略帮助您将压缩应用到大量的现有数据,释放该数据当前使用的磁盘空间,将此空间释放到文件系统。在首次实现行或索引压缩时或当从更早的 DB2 版本升级到 DB2 10.1 时,您会发现此信息非常有用。

对现有数据应用压缩

对现有数据应用压缩的最直观的方法是执行经典表重组。如果更改了行或值压缩的设置,则可执行指定了 RESETDICTIONARY 选项的 REORG TABLE 命令。如果一些表包含 XML 列,还应该指定 LONGLOBDATA 子句,以便压缩非内联的 XML 文档。如果仅更改索引的压缩设置,REORG INDEXES ALL 命令已足以压缩索引数据。没有必要对基础表的数据执行全面重组。举例而言,如果从 DB2 9.5 升级到 DB2 10.1,并且已经启用了行压缩,那么您可能应该考虑执行索引重组,而不是对所有表数据进行全面重组。

如果无法让表处于离线状态,那么还可考虑使用 ADMIN_MOVE_TABLE() 存储过程,该存储过程自 DB2 9.7 开始提供。可以使用此过程将活动表中存储的数据迁移到一个具有相同名称的新数据表对象中,该表不一定位于相同的存储位置。ADMIN_MOVE_TABLE() 过程提供了一种方式来采用与经典表重组相同的方式有效地重组表,但不需要任何宕机时间,数据在迁移期间仍然可以保持在线和可用。

ADMIN_MOVE_TABLE() 过程所构建(或重新构建)的表级压缩字典与在表重组期间构建的字典具有相同的质量。要构建或重新构建压缩字典,ADMIN_MOVE_TABLE() 过程执行以下步骤:

  1. 收集表中所有行的一个 Bernoulli 抽样。
  2. 从该抽样构建一个新的表级压缩字典。
  3. 将该字典插入目标表,然后再开始执行复制阶段,所以在复制阶段插入到目标表时,行已经被压缩。

下面的示例展示了如何以最直观的方式执行一个在线表迁移操作。

  CALL SYSPROC.ADMIN_MOVE_TABLE('DB2INST1','ACCTCR',
                           '','','','','','','','','MOVE')

可使用 ADMIN_MOVE_TABLE_UTIL() 过程对在线表迁移操作的参数和行为执行细粒度控制,比如确定用于字典构建的抽样大小。但是,即使在标准 'MOVE' 执行模式下调用该函数,构建的压缩字典也是最佳的。

不同于经典表重组,ADMIN_MOVE_TABLE() 过程的默认行为是重新构建字典。因为仅使用了表数据的一个较小的随机抽样,所以与不重新构建字典相比,重新构建字典通常不会导致过量性能开销。

您可能发现在从更早的 DB2 版本升级数据库时,ADMIN_MOVE_TABLE() 过程特别有用。与此同时,您可以使用该过程在表空间之间迁移表和更改其他参数,比如列数据类型。

管理磁盘空间使用

向现有表应用压缩会减少分配给这些表的页数。但是,应用压缩不会直接影响到 DMS 的磁盘空间使用或自动存储表空间。这些表空间可使用更大数量的未用盘区。

当首次实现行和索引压缩时,一种建议的实践是重新计算表空间容器的利用率和预计的数据增长速率。启用压缩之后,表空间利用率可显著减少,数据库可能花很长时间才会增长到足以使用最初释放的空间。因此,您可能希望能够减少表空间容器大小,向其他用户提供更多磁盘空间。

要有效地减少数据库的磁盘占用,必须减少数据库使用的表空间容器的大小。而且确定可多大程度地减少表空间容器大小的关键因素是高水位线 (high water mark)。(高水位线表示一个表空间中分配的最大页面数;它是一个仅适用于 DMS 的概念,还包含自动存储表空间。)

在创建表、扩展现有表,或执行不使用临时表空间的经典表重组时,高水位线可能增长。要降低高水位线,可以丢弃或截断拥有高水位线处的盘区的表。但是,丢弃、截断或重组其他对象不会影响高水位线,只会导致在高水位线以下创建更多未使用的盘区。这些高水位线之下的未使用盘区仅可在创建新对象或对象增长时重用。只有高水位线以上的盘区才可以回收并返回到操作系统。因此,减少磁盘空间占用的关键是降低高水位线,截断表空间容器。执行此任务的方式依赖于您使用的表空间类型、您使用哪个 DB2 版本创建这些表空间,以及您正在使用哪个 DB2 版本。(降低高水位线和释放空间的基数已在本文的 将未使用的空间返回到文件系统 一节中介绍。)

验证行压缩和避免常见错误

如前面所述,可以通过查询系统目录,获取表和索引当前的压缩设置。在 SYSCAT.TABLES 视图中,COMPRESSION 和 ROWCOMPMODE 列包含有关每个表当前的压缩设置的信息。SYSCAT.INDEXES 视图中的 COMPRESSION 列提供了有关每个索引的压缩设置的信息。RUNSTATS 命令可以填充所有这些列。

SYSCAT.TABLES 视图中的其他列提供了行压缩执行方式的更深入洞察:

  • 最重要的度量指标可在 PCTPAGESSAVED 列中找到。它表明您目前通过行压缩方式在一个表上节省了多少空间。
  • 从 PCTROWSCOMPRESSED 列,可以确定压缩了表中的多少行。
  • AVGCOMPRESSEDROWSIZE 列提供了所有压缩的行的平均大小。在大部分实际情形中,压缩的行的百分比应该接近 100%。在此情况想,压缩的行的平均大小等于 AVGROWSIZE 列中包含的平均行大小。

如果一个表中压缩的行的百分比比 100% 低得多,此情形可能是因为以下常见问题之一所导致:

  • 您的表可能位于一个常规表空间中,并且压缩可能已导致平均行大小非常小。对于常规表空间中的表,有效的最小行大小受每个页面可包含最多 255 行的事实限制。如果平均行大小接近或低于该比率,可以考虑将常规表空间转换为大表空间。为此,需要执行指定了 CONVERT TO LARGE 选项的 ALTER TABLESPACE 语句。或者使用 ADMIN_MOVE_TABLE() 过程将表迁移到一个大表空间。
  • 如果在一个包含数据的现有表上启用行压缩,则会在表增长时通过 ADC 自动构建表级字典。在执行经典表重组或使用 ADMIN_MOVE_TABLE() 函数之前,现有的数据会保持其未压缩形式。
  • 当创建启用了经典行压缩的表并开始填充该表时,系统会在表大小达到 ADC 阈值 2 MB 时自动构建表级字典。但是,表开头的行保持未压缩状态。如果表只有几 MB 大。这个最初的未压缩行集合可能成为存储在该表中的总行数的很大一部分。

如果上述任何情形都不符合,则可以确定表是否包含随机数据。例如,一个表可能有一个大型的 CHAR FOR BIT DATA 或内联 LOB 列,其中包含由应用层以某种方式压缩的二进制数据。在这些情况下,可能无法使用行压缩进一步压缩数据,并且不应在该表上启用行压缩。

在对 MDC 表应用行压缩时,请特别注意。单元格大小和数据密度是 MDC 表的物理设计的重要考虑因素,在选择合适的维度时发挥着重要作用。在某些情况下,可选择集群维度,使单元格可使用很少量的页面。应用行压缩可减少每个记录的大小和单元格的平均大小。如果行压缩导致平均单元格大小接近或小于一个块的大小,那么您可能不会发挥出存储空间节省的最大潜力。这是因为 MDC 表中的空间分配是在块级别上完成的。部分使用的块会使用磁盘上的一个完整盘区,但可能包含大量空闲空间。如果知道自己将使用行压缩,那么请记得在预计单元格大小时考虑压缩率。如果决定在现有的 MDC 表上应用行压缩,则需要重新验证单元格大小计算结果。您可能会发现,有必要粗粒度化 (coarsify) 一些维度或减少表空间的盘区大小。

确认对您考虑执行压缩的所有索引启用了索引压缩。需要特别注意系统生成的索引,比如为主键和惟一列隐式创建的索引。如果创建一个表而没有启用行压缩,然后使用 ALTER TABLE 语句启用行压缩,那么在为表启用压缩之前创建的现有索引将保持未压缩状态;您必须通过执行 ALTER INDEX 语句为这些索引显式启用索引压缩。对于启用了压缩的索引,PCTPAGESSAVED 列提供了有关存储空间节省的信息。


将未用的空间返回给文件系统

通过深度压缩减少保存一个表的数据所需的存储空间量之后,您可能希望调整该表所在的表空间大小,使回收的任何存储空间可用在其他地方。如果使用了 SMS 表,回收的任何存储空间将在表重组流程中自动返回到文件系统。但是,使用 DMS 表空间时不是这样的。相反,DMS 表空间(以及自动存储表空间,它们在默认情况下是 DMS 表空间)可通过执行适当形式的 ALTER TABLESPACE SQL 语句来进行调整。例如,要将对表空间 TBSP1 使用的每个容器分配的存储空间量减少 200 MB,可以执行一条 ALTER TABLESPACE 语句,该语句类似于以下语句:ALTER TABLESPACE tbsp1 REDUCE (ALL CONTAINERS 200 M)

您也可以通过丢弃一个或多个存储容器来回收空间,而不调整所有这些容器。但是,实际可返回到文件系统用于重新分配的存储空间量依赖于调整的表空间的高水位线位置。

高水位线对空间重新分配的影响

只要将一行数据存储在一个表中,DB2 就会为该行分配一个惟一记录标识符,这个标识符称为 RID。在 DB2 9 之前,RID 由 1 个 3 字节页面标号和 1 个 1 字节插槽 (slot) 编号组成。插槽编号是输入一个插槽目录的数组,它包含数据页面上以物理形式存储该行的数据的偏移位置;页面标号表示数据页面本身。DB2 9 及其更高版本能够支持 4 字节 RID 和 6 字节 RID,后者由 1 个 4 字节页面编号和 1 个 2 字节插槽编号(位于一个 DMS LARGE 表空间中的表使用 6 字节 RID) 组成。因此,您现在可以拥有包含超过 255 行的数据页面(使用 4 字节 RID 的旧限制),单个表分区在使用 4K 页面时可增长到 2 TB(使用 32K 页面时可增长到 16 TB)。在 DB2 9 及其更高版本中,默认情况下会对创建的所有新的自动存储表空间和 DMS 表空间使用 6 字节 RID。

DB2 索引使用相对于表空间的 RID 来引用基础表记录。(索引是一个应用基础表中的行的指针的有序集合。)这意味着,一个索引中的每个键指向一个表空间中的页面 Y 中的插槽 X,而不是指向基础表的页面 Y 中的插槽 X。因此,DB2 无法在一个表空间中随意移动盘区。如果它这么做了,那么索引中存储的 RID 会指向错误的数据,每次执行移动后,都必须重新构建引用该表空间中的数据的每个索引。

使用相对于表空间的 RID 可以提高性能,因为它消除了查找某个表的特定页面位于表空间中的位置的步骤,该步骤必须通过扫描表的盘区图页面来完成。因为 DB2 无法更改盘区在表空间中的位置,所以只可以释放高水位线之上的未用的存储空间。

压缩表数据所需的离线表重组操作的执行方式可能对表空间的高水位线带来重大影响。如果使用临时表空间来重组和压缩表数据,得到的表的版本会在临时表空间中构造,它的数据页面会复制到原始表空间中的原始表对象上,该表使用的存储空间会被截断。图 7 展示了使用临时表空间重组并压缩一个包含 4 个表(分别名为 TABLE_1、TABLE_2、TABLE_3 和 TABLE_4)的表空间中的所有 4 个表之前和之后,该表空间的外观。

图 7. 使用临时表空间的表重组操作对表空间的高水位线的影响
该图显示,在压缩之后,高水位线变得更高,因为空闲空间是零散的

压缩所有 4 个表中的数据后,可用的空闲空间将会更多;但是,这些领先空间分散在整个表空间中,所以高水位线没有显著降低。

如果未使用临时表空间来重组和压缩表数据,该表的新版本会在与原始表相同的表空间中创建,而且最终会删除原始表。由于此行为,重组和压缩表的顺序和这些表位于表空间中的位置(不幸的是,没有确定此位置的轻松方式)都会对表空间内的表布局和表空间的高水位线位置产生重大影响。图 8 显示了我们包含 4 个表(TABLE_1、TABLE_2、TABLE_3 和 TABLE_4)的原始表空间在按以下顺序重组和压缩(未使用临时表空间)其中的所有 4 个表之前和之后的外观:TABLE_1、TABLE_2、TABLE_3 和 TABLE_4。

图 8. 不使用临时表空间的表重组操作对表空间的高水位线的影响
该图显示了减少的高水位线

在本例中,我们最终得到了比开始执行重组和压缩操作时更高的高水位线。但是,如果要再次重组和压缩表 TABLE_1,该表将移动到表空间中的空闲空间开头,高水位线将显著降低。图 9 显示了对 TABLE_1 执行第二次重组和压缩之后表空间的外观。

图 9. 在表 TABLE_1 上执行第二个重组/压缩操作来降低表空间的高水位线
该图显示了指定第二次重组和压缩后的高水位线

请注意,图 7、图 8 和图 9 中的示例基于这样一个假设:TABLE_1、TABLE_2、TABLE_3 和 TABLE_4 是依次创建和填充的(一次一个),并且表空间 TBSP1 已全面压缩。在现实中,此示例可能是最糟的情景。当一个表空间中存在多于一个表时,我们通常会看到来自不同表的盘区分散在整个表空间中。评估存在的盘区碎片化程度会变得更加复杂,但可能没有这些插图中所示的那么明显。因此,实际的高水位线影响可能小得多。

当开始向同一个表空间添加索引对象和大对象 (LOB) 时,事情会变得更加复杂,并且很难准确预测将会发生什么。您可以使用命令 db2dart /DHWM 显示一个表空间中所有表的盘区布局,使用命令 db2dart /LHWM 解释此布局并生成一系列步骤,您可以执行这些步骤来降低高水位线。但是,保证内容尽可能紧凑地布局的惟一方式是:通过卸载和重载表空间的表,从头重新构建整个表空间。只有这样,您才能够将通过压缩回收的所有存储空间返回给操作系统,将它们用于重新分配。

DB2 9.7 及其更高版本中可回收的存储

在 DB2 9.7 或其更新版本中创建的非临时 DMS 和自动存储表空间支持可回收的存储。对于这些表空间,数据库管理器可管理容器中的盘区的物理位置。此机制称为盘区移动,可以使用该机制将表空间容器中未用的空间合并到容器的物理位置末尾。合并之后,便可降低高水位线,然后表空间容器就可以缩减到最小大小。图 10 显示了在使用盘区移动来回收自动存储表空间中的未用存储之前和之后,表空间的外观。

图 10. 如何通过盘区移动降低自动存储表空间的高水位线
该图显示一个通过盘区移动而降低的自动存储表空间的高水位线

要使用可回收的存储,可以使用 ALTER TABLESPACE 语句降低高水位线和缩减表空间容器。降低高水位线的过程涉及到盘区移动,可能会花费一些时间。降低高水位线之后,可通过将高水位线之上的未用盘区返回给文件系统来减少容器的大小。

要确定减少 DMS 或自动存储表空间的大小的程度,可以执行 MON_GET_TABLESPACE() 表函数,如下所示。

清单 9. 计算 DMS 或自动存储空间的大小减少的查询
  SELECT SUBSTR(TBSP_NAME, 1, 15) AS TBSP_NAME,
                TBSP_FREE_PAGES,
                TBSP_PAGE_SIZE * TBSP_FREE_PAGES / 1024 / 1024
                  AS TBSP_RECLAIMABLE_MB
    FROM TABLE(MON_GET_TABLESPACE('TBSP_USR_D_1', NULL))

下面的示例结果集表明,表空间 TBSP_USR_D_1 可减少大约 2300 万个页面,相当于 365 MB 的磁盘空间。

清单 10. 查询结果
  TBSP_NAME       TBSP_FREE_PAGES      TBSP_RECLAIMABLE_MB 
  --------------- -------------------- --------------------
  TBSP_USR_D_1                23369760               365150

    1 record(s) selected.

可使用带 REDUCE MAX 子句的 ALTER TABLESPACE 语句,轻松地将自动存储表空间缩减为最紧凑的格式:ALTER TABLESPACE tbsp_usr_d_1 REDUCE MAX

对于 DMS 表空间,降低高水位线和减少容器是一个分两步的过程,如下所示:

  ALTER TABLESPACE ts_dat_d LOWER HIGH WATER MARK;
  ALTER TABLESPACE ts_dat_d REDUCE (ALL CONTAINERS 100 G);

当将数据库从早期的 DB2 版本升级到 DB2 9.7 或其更高版本时,可以考虑采用以下步骤来获得可回收存储的收益:

  1. 为所有自动存储或 DMS 表空间创建新的表空间。
  2. 在表上启用行和索引压缩。
  3. 使用 ADMIN_MOVE_TABLE() 将表从旧表空间迁移到新表空间。

应该在迁移表之前启用行和索引压缩,这样才能在迁移过程中压缩它们。


压缩和 Load 实用程序

DB2 9.5 中引入的另一个重要更改是,在对启用了深度压缩的表执行加载操作时的行为。在 DB2 9 中,如果已经为一个表创建了压缩字典,那么 Load 实用程序会在加载数据时使用该字典压缩数据。但是,如果不存在压缩字典,Load 实用程序就不会在加载操作中构建压缩自动。自 DB2 9.5 开始,只要加载的表启用了压缩并且执行了 LOAD REPLACE 操作,Load 实用程序就可以构造一个压缩字典。该操作通过执行指定了 REPLACE KEEPDICTIONARYREPLACE RESETDICTIONARY 选项的 LOAD 命令来发起。(如果加载的表启用了压缩,并且传入的数据量触发了 ADC,LOAD INSERT 操作也可能导致创建一个压缩字典。)

如果执行指定了 REPLACE KEEPDICTIONARYREPLACE RESETDICTIONARY 选项的 LOAD 命令,并且不存在压缩字典,则会创建一个新字典。如果使用 KEEPDICTIONARY 选项,构建压缩字典所需的数据量将受 ADC 的策略控制。因此,一些数据将以未压缩形式存储在表中。创建字典后,加载的剩余数据会使用新的压缩字典进行压缩。另一方面,如果指定 RESETDICTIONARY 选项,构建字典所需的数据量不会受到 ADC 的策略控制,并且只需加载了一行,即可构建一个压缩字典。

如果执行指定了 REPLACE KEEPDICTIONARYREPLACE RESETDICTIONARY 选项的 LOAD 命令,并且已经存在一个压缩字典,则会重新创建现有的字典 (RESETDICTIONARY) 或保持不变 (KEEPDICTIONARY),并且表中的数据会使用现有字典或新的字典进行压缩。

要在执行加载操作期间位一个启用了压缩的表 EMPLOYEE 创建新压缩字典,可执行以下类似的命令:LOAD FROM datafile.del OF DEL REPLACE RESETDICTIONARY INTO employee

当执行此命令时(假设 EMPLOYEE 表没有压缩字典),文件 DATAFILE.DEL 中的一些记录将以未压缩形式加载到 EMPLOYEE 表中。只要加载了 1-2 MB 数据,ADC 就会使用该数据构建一个压缩字典,剩余记录在加载时会直接使用该压缩字典压缩并写入表中。


备份映像和日志归档的压缩

自 DB2 Universal Database 8 开始,您就可以压缩备份映像。自 DB2 10.1 开始,也可以对日志归档应用压缩。无论是否拥有 DB2 Storage Optimization Feature 的许可,都可以使用这些功能。(用于压缩备份映像和归档的日志的默认算法类似于 UNIX®compress(1) 实用程序使用的算法。)

备份压缩

可以对每个备份映像独立地启用备份压缩。当执行备份操作时,需要指定 COMPRESS 子句,例如: BACKUP DATABASE TDB2 to /vol_aux/backups/ COMPRESS

如果使用了行压缩和索引压缩,并且遵循减少表空间的容器大小的指导原则,那么可以显著减小数据库的总大小。结果,您的备份映像将比禁用行和索引压缩时更小。与此同时,在备份映像上应用压缩可实现的额外的空间节省可能显著减少。在有许多表使用自适应样压缩时,这种节省尤为显著。但是,备份映像上的压缩也可以压缩元数据、LOB、目录表,以及无法以任何其他方式压缩的其他数据库对象。

在决定是否压缩备份映像时,最重要的指标是执行备份时的 CPU 和磁盘利用率。备份压缩可带来大量的 CPU 开销。只有在备份流程仅受到 I/O 限制时,才应使用备份压缩。例如,如果将备份映像存储在一个未分散在不同的物理磁盘上的卷上,或者如果备份到网络附加或非本地存储介质上,就可能出现这样瓶颈。在这些情况下,整个备份流程会增加 CPU 利用率,但 I/O 开销的节省可有效缩短备份时间。

如果将备份存储在 Tivoli® Storage Manager (TSM) 软件上,则应该使用 TSM 中内置的压缩和重复数据删除功能。如果保存了多个最新的备份映像,重复数据删除逻辑可能导致更多的存储空间节省。

如果只有部分表使用行压缩和索引压缩,基于各自的压缩设置将这些表和索引分离到不同的表空间中是一种不错的做法。另外,可以考虑在表空间级别上执行备份,而不是在数据库级别上。在这种情况下,可以平衡压缩设置,仅压缩包含未压缩的表和索引的这些表空间的备份。

归档日志压缩

如果为数据库配置了日志归档,您可通过数据库配置参数对这些日志归档启用压缩。可以独立地对主要归档方法、辅助归档方法和相应的归档位置启用或禁用日志归档压缩。日志归档压缩需要数据库管理员对归档流程进行处理,也就是说,您必须将归档方法设置为 DISKTSMVENDOR。下面的示例展示了如何设置启用了压缩的主要日志归档和基于磁盘的日志归档:

  UPDATE DB CFG FOR TDB2 USING LOGARCHMETH1 DISK:/vol_aux/archive/tdb2;
  
  UPDATE DB CFG FOR TDB2 USING LOGARCHCOMPR1 ON;

对于辅助归档方法,可以采用类似方法启用压缩。

启用压缩之后,日志归档压缩是全自动的。在将日志盘区从归档日志路径迁移到归档位置时,数据库管理器会自动压缩它们。在检索日志文件时(可能在 ROLLBACKROLLFORWARD 操作期间发生),在将压缩的日志文件从归档迁移到活动或溢出日志路径时,数据库管理器会自动扩展这些文件。如果在恢复期间,数据库管理器在活动或溢出日志路径中遇到一个压缩的日志盘区,它会自动扩展该盘区。例如,如果您手动从归档位置将日志盘区检索到活动或溢出日志路径,就有可能出现这种情况。

在决定是否在日志归档上启用压缩时,需要考虑的一些因素与备份压缩的考虑因素类似。请检查可供归档位置使用的 I/O 带宽,查看它是否是归档期间的瓶颈。

如果日志归档在非本地卷或未分散在多个磁盘上的卷上,那么可以考虑启用压缩。此外,如果将日志归档到一个磁盘暂存位置,以便以后通过 db2tapemgr 实用程序传输到磁带上,那么可以考虑启用压缩。在这种情况下,压缩有助于减少将归档日志传输到磁带所花费的时间。

如果归档到 TSM,可以考虑使用它内置的压缩工具。日志归档的行为类似于 DB2 10.1 中的压缩工具,因为它们采用了相同的算法。与备份压缩不同的是,重复数据删除一般不会带来额外的收益。

在使用行和索引压缩时,写入事务日志的一些数据已经是压缩格式。因此,计入日志的数据量比在未压缩的表上执行相同操作时需要记入日志的数据量少。但是,即使广泛使用行压缩和索引压缩,事务日志中通常仍有足够的元数据和其他未压缩内容,可供您在几乎任何日志归档上实现重大的存储空间节省。


致谢

作者感谢 Bill Minor 对本文的贡献。

参考资料

学习

获得产品和技术

  • 使用 IBM 产品评估试用版软件 构建您的下一个开发项目,这些软件可直接从 developerWorks 下载。
  • 现在您可以免费使用 DB2。下载 IBM 软件下载:IBM DB2 Express-C 10.1,这是一个面向社区的免费的 DB2 Express Edition 版本,提供了与 DB2 Express Edition 相同的核心数据特性,为构建和部署应用程序提供了一个牢固基础。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=828046
ArticleTitle=使用 DB2 10 中的深度压缩来优化存储
publish-date=07302012