Informix 11.70 系统管理认证考试 919 准备教程,第 2 部分: Informix 空间管理

在本教程中,您将学习如何在 IBM Informix® 数据库上配置和管理存储空间,创建这些存储空间的实用程序,以及如何使用碎片和各种功能来优化数据库中的存储。本教程帮助您为参加 Informix v11.70 系统管理认证考试 919 的第 2 部分做准备。

Edgar Sanchez, 高级支持工程师, IBM China

Edgar Sanchez 的照片Edgar D. Sanchez 是佛罗里达州 Coral Gables 市 IBM Latin American Support Call Center 的软件工程师,有超过 20 年的工作经验,主要担任 IBM Informix Dynamic Server 和 DB2 的数据库支持工程师。他还担任过高级支持工程师、地区高级支持和 RDBMS 客户的教员(培训员)。



Carolina Leme, 技术支持工程师, IBM China

Carolina Leme 的照片Carolina Leme 是一名 IBM Informix 技术支持工程师。自 2006 年起,他开始研究将 IBM Informix 产品移植到各种平台上,并一直提供 Informix 支持。在 IBM,Carolina 为 Informix 用户提供过 7、9、10、11.50 和 11.70 版本的 IBM Informix 数据库支持。



2012 年 8 月 09 日

开始之前

免费下载:IBM® Informix® 11.7 试用版(包括 Ultimate Edition、Developer Edition 和 Innovator-C Edition)
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

关于本系列

正在考虑获得 Informix 11.70 版的系统管理认证(考试 919)?如果是,那么您来对地方了。这个 认证准备教程系列 涵盖您在参加考试前需要理解的所有主题。即使您目前没有获取认证的想法,这一系列教程也是您开始了解 Informix 11.70 中的新功能的不错地方。

关于本教程

在本教程中,您将学习如何使用 IBM Informix 工具创建 dbspace、sbspace 以及时态 dbspace。您将学习创建和管理表碎片,以及使用存储优化特性,比如压缩。此处提供的材料主要涵盖考试第 2 部分(名为空间管理)中的目标。

目标

完成本教程的学习后,您应该能够:

  • 创建 dbspace 和 sbspace
  • 向 dbspace 或 sbspace 添加块区
  • 重命名 dbspace
  • 在块区中镜像一个 dbspace 或 sbspace
  • 使用表碎片
  • 使用附加或分离来向碎片表添加或删除碎片
  • 使用数据压缩来优化存储

前提条件

要理解本教程中介绍的内容,您必须熟悉以下内容:

  • IBM Informix 环境(配置文件和参数、安装和管理)
  • 数据库服务器命令(onstat、onmode、oncheck 和 dbschema)
  • IBM Informix 概念和术语(dbspace、块区、物理日志、逻辑日志、检查点等)

系统需求

无需 IBM Informix 的副本即可完成本教程的学习。但是如果下载 Informix Innovator-C Edition 的免费试用版(请参阅 参考资料)以供在学习本教程的过程中使用,您将从本教程获得更多知识。


配置和管理存储空间

存储空间是一个物理区域,这是 IBM Informix 存储数据的区域。有一些不同类型的存储空间可供 IBM Informix 使用,包括 dbspace、blob 空间、智慧 blob 空间和外部空间。您可以在数据库服务器上创建最多达 32,766 个存储空间。

以下实用程序可帮助您管理存储空间:

  • onspaces 实用程序
  • SQL 管理 API 命令
  • OpenAdmin Tool (OAT)

理解 dbspace

dbspace 是一个逻辑单元,其中可包含 1 到 32,766 个块区。将数据库、表、逻辑日志文件和物理日志放在 dbspace 中。

使用默认页面大小的 dbspace

要使用 onspace 创建一个标准的 dbspace,您必须以用户 informixroot 的身份登录。在 Windows 上,Informix-Admin 组中的用户可创建一个 dbspace。请确保数据库服务器处于在线、管理或休眠模式。

使用 onspaces -c -d 选项创建 dbspace 或临时 dbspace,如 清单 1 中所示。

清单 1. 创建 dbspace
onspaces -c -d < dbspace_name> -p < pathname or
drive> -o < offset> -s < size> -m--< pathname> < offset>

一个 dbspace 的最大大小等于最大块区数乘以一个块区的最大大小。(最大块区数是每实例 32,766 个。一个块区的最大大小等于 2147483647 个页面乘以页面大小。)

清单 2 展示了如何创建一个 10 MB 的镜像 dbspace dbspce1,它在主要和镜像块区上都具有 5000 KB 的偏移;使用默认页面大小;使用 UNIX 上的原始磁盘空间。

清单 2. 示例镜像 dbspace 创建
onspaces -c -d dbspce1 -p /dev/raw_dev1 -o 5000 -s 10240 -m
/dev/raw_dev2 5000

清单 3 展示了如何在 Windows 上创建一个 5 MB 的 dbspace dbspc3,它具有一个离原始磁盘空间(驱动器 e:)200 KB 的偏移。

清单 3. 示例 dbspace 创建
onspaces -c -d dbspc3 \\.\e: -o 200 -s 5120

具有非默认页面大小的 dbspace

如果想要使键长度比可用于默认页面大小的键长度更长,那么您可以为标准或临时 dbspace 指定一个页面大小。Root dbspace 具有默认的页面大小。如果您希望指定页面大小,该大小必须是默认页面大小的整数倍,并且不能大于 16 KB。

对于具有充足存储空间的系统,更大的页面大小所提供的性能优势包括:

  • 减少 b-型树索引深度,即使是较小的索引键也是如此
  • 缩短检查点时间

您还可通过执行以下操作,获得额外的性能优势:

  • 将当前跨越多个默认页面大小页面的长行分组在同一个页面上
  • 为临时表定义一个不同的页面大小,使临时表具有一个独立的缓冲池

您可以使用 BUFFERPOOL 配置参数创建一个与 dbspace 的页面大小对应的缓冲池。表可以放在一个 dbspace 中,对该表的索引可以放在另一个 dbspace 中。这些分区的页面大小可以不同。可以执行以下步骤来指定 dbspace 的页面大小。

  1. 如果还未启用此模式,使用 onmode -BC 命令启用大块区模式。默认情况下,当首次初始化或重新启动 IBM Informix 时,IBM Informix 首先会启用大块区模式。有关 onmode 实用程序的信息,请参阅 IBM Informix 管理员参考指南(参阅 参考资料)。
  2. 创建一个与 dbspace 的页面大小对应的缓冲池。您可以使用 onparams 实用程序或 BUFFERPOOL 配置参数。此操作应该在创建 dbspace 之前执行。如果您创建的 dbspace 页面大小没有相应的缓冲池,则 IBM Informix 会使用在 onconfig 配置文件中定义的默认参数自动创建一个缓冲池。不能有多个具有相同页面大小的缓冲池。
  3. 在创建 dbspace 时定义它的页面大小。您可以使用 onspaces 实用程序或 ON-Monitor。例如,如果创建一个具有 6 KB 页面大小的 dbspace,则必须创建一个 6 KB 的缓冲池。如果没有为新缓冲池指定页面大小,IBM Informix 将使用操作系统的默认页面大小(Windows 上为 4 KB,大部分 UNIX 平台上为 2 KB)作为缓冲池的默认页面大小。

临时 dbspaces

要指定在何处分配临时文件,可以创建临时 dbspace。要定义临时 dbspace,请执行以下步骤。

  1. 使用带 -c -d -t 选项的 onspaces 实用程序
  2. 使用 DBSPACETEMP 环境变量或 DBSPACETEMP 配置参数来指定可供数据库服务器用于临时存储的 dbspace。

DBSPACETEMP 配置参数可包含具有非默认页面大小的 dbspace。尽管您可以在 DBSPACETEMP 的参数列表中包含具有不同页面大小的 dbspace,但数据库服务器仅使用具有相同页面大小的 dbspace 作为第一个列出的 dbspace。

如果创建多于一个临时 dbspace,这些 dbspace 必须位于独立的磁盘上,以优化 I/O。清单 4 展示了如何创建一个 5 MB 大且具有偏移 5000 KB 的临时 dbspace temp_space。

清单 4. 临时 dbspace
onspaces -c -t -d temp_space -p /dev/raw_dev1 -o 5000 -s 5120

理解 sbspace

sbspace 是一个逻辑存储单元,其中包含一个或多个存储智慧大对象的块区。智慧大对象包括字符大对象 (CLOB) 和二进制大对象 (BLOB) 数据类型。用户定义的数据类型也可以使用 sbspace。

创建默认的 sbspace

执行以下步骤来创建一个默认的 sbspace。

  1. 将 ONCONFIG 参数 SBSPACENAME 设置为您默认 sbspace 的名称。在启动数据库服务器之前,必须更新 ONCONFIG 文件。清单 5 展示了如何将默认 sbspace 命名为 sbsp1。
    清单 5. 将默认 sbspace 命名为 sbsp1
    SBSPACENAME sbsp1 # Default sbspace name
  2. 使用 onspaces 实用程序创建 sbspace。清单 6 展示了如何在分区 /dev/sbspace 中创建一个名为 sbsp1 的 sbspace。
    清单 6. 在分区 /dev/sbspace 中创建一个 sbspace
    onspaces -c -S sbsp1 -g 2 -p /dev/sbspace -o 0 -s 100000 -Df
    "LOGGING=ON"

    示例 sbspace 的初始偏移为 0,大小为 100 MB,而且打开了日志功能。

配置 sbspace

您可以使用 onspaces 实用程序的 -Df 选项为 sbspace 参数指定新的默认值。这一节将介绍如何记录 sbspace 日志,以及如何为存储在 sbspace 中的智慧大对象自定义大小规格。

打开日志功能

在创建 etx 索引时必须使用打开了日志功能的 sbspace;否则 CREATE INDEX 语句将失败。onspaces 实用程序创建的 sbspace 默认已关闭日志,以保护资源。但是,etx 索引用户可从日志中获益。举例而言,如果在更新 etx 索引时发生断电,索引可能会损坏。如果包含索引的 sbspace 关闭了日志功能,截至到损坏发生时的更改将无法恢复。在这种情况下,要确保索引完整性,必须丢弃并重新创建索引。如果打开了日志功能,通常可以恢复 etx 索引。

在使用 onspaces 实用程序创建 sbspace 时,可通过指定 -Df "LOGGING=ON" 来打开日志,如 清单 7 中所示。

清单 7. 打开日志功能
onspaces -c -S sbsp1 -g 2 -p /dev/sbspace -o 0 -s 100000 -Df
"LOGGING=ON"

向 dbspace 或 sbspace 添加块区

在 dbspace 或 sbspace 装满或需要更多磁盘空间时,可添加一个块区。使用 onspaces 实用程序添加块区。在大部分平台上,最大块区大小为 4 TB,而在另一些平台上,最大块区大小为 8 TB。

注意:新添加的块区(以及其关联镜像,如果存在的话)可立即使用。如果向一个镜像的存储空间添加块区,那么您还要添加一个镜像块区。

要在 UNIX 上使用 onspaces 添加块区,必须以用户 informixroot 的身份登录。在 Windows 上,Informix-Admin 组中的用户可添加块区。请确保数据库服务器处于在线模式、管理模式、休眠模式,或者处于快速恢复模式的清理阶段。

清单 8 向 blobsp3 添加了一个 10 MB 的镜像块区。为主要和镜像块区都指定了 200 KB 的偏移。如果不添加镜像块区,则可以省略 -m 选项。

清单 8. 添加镜像块区
onspaces -a blobsp3 -p /dev/raw_dev1 -o 200 -s 10240 -m
/dev/raw_dev2 200

清单 9向 dbspace dbspc3 添加了原始磁盘空间上偏移为 5200 KB 的一个 5 MB 块区。

清单 9. 添加原始磁盘空间
onspaces -a dbspc3 \\.\e: -o 5200 -s 5120

您也可以定义在应用程序需要更多磁盘空间时使用 IBM Informix 自动扩大块区大小的信息。如果拥有可扩展的块区,则无需添加新块区或花时间尝试确定哪个磁盘空间(dbspace、临时 dbspace、sbspace、临时 sbspace 或 blobspace)何时将耗尽空间。

重命名 dbspace

如果您是用户 informix 或具有 DBA 权限,并且数据库服务器处于休眠模式(而不是任何其他模式),您可以使用 onspaces 实用程序重命名 dbspace。

要重命名 dbspace,可使用以下 onspaces 实用程序命令,如 清单 10 中所示。

清单 10. 重命名 dbspace
onspaces -ren old_dbspace_name-n new_dbspace_name

您可以重命名标准 dbspace 和其他所有空间,包括 blobspace、智慧 blobspace、临时空间和外部空间。但是,不能重命名任何关键 dbspace,比如 root dbspace 或包含物理日志的 dbspace。

您可以在启用企业复制时或在主要数据库服务器上启用数据复制时重命名 dbspace 或 sbspace。您不能在辅助数据库服务器上或在企业复制配置中包括辅助数据库服务器时重命名 dbspace 或 sbspace。

重命名 dbspace 只会更改 dbspace 名称;它不会重组数据。重命名 dbspace 的命令会在存储 dbspace 名称的每个地方更改该名称。这包括磁盘、系统目录、ONCONFIG 配置文件和内存数据结构的保留页面。

注意:重命名 dbspace 后,您应该对重命名的 dbspace 和 root dbspace 执行 0 级归档。

理解镜像

镜像是将一个定义的 dbspace、blobspace 或 sbspace 的一个主要块区与一个相同大小的镜像块区配对的战略。

每次向主要块区写入时,都会向镜像块区执行相同的写入操作,如 图 1 中所示。如果主要块区上发生故障,镜像支持您在恢复主要块区之前从镜像块区读取和向其写入数据,所有这些都不会中断用户对数据的访问。

当使用磁盘镜像时,数据库服务器将数据写入两个位置。镜像消除了由于存储设备故障而导致的数据丢失。如果镜像的数据出于任何原因变得不可用,数据的镜像会立即并透明地向用户公开。

图 1. 同时向主要块区和镜像块区写入数据
数据库服务器连接主要块区和镜像块区节点并在它们之上写入数据

创建镜像块区

当指定镜像块区时,数据库服务器将所有数据从主要块区复制到镜像块区。这个复制过程称为恢复。镜像会在恢复完成后立即执行。

如果在包含逻辑日志文件的 dbspace 内开始镜像块区,标志镜像开始的恢复过程将被延迟。包含逻辑日志文件的 dbspace 的镜像在您创建了 root dbspace 的 0 级备份之后才会开始。该延迟可确保如果包含这些逻辑日志文件的主要块区在 dbspace 还原期间变得不可用,数据库服务器可使用镜像的逻辑日志文件。

0 级备份更新的数据库服务器配置信息(包括有关新镜像块区的信息),从根 dbspace 的保留页面复制到备份。如果执行数据还原,如果主要块区变得不可用,在备份开始时更新的配置信息会要求数据库服务器查找逻辑日志文件的镜像副本。如果这个新的存储空间备份信息不存在,数据库服务器则无法利用镜像的日志文件。

出于类似的原因,您无法在创建 dbspace 备份时镜像包含逻辑日志文件的 dbspace。必须位于 dbspace 备份磁带的第一个块中的新信息无法在备份开始后复制到这里。

清单 11给出了一个使用 onspaces 命令向镜像添加块区的示例。使用 -m 选项指定镜像块区路径和偏移。

清单 11. 镜像块区路径和偏移
onspaces -a db_acct -p /dev/chunk2 -o 5000 -s 2500 -m
/dev/mirror_chk2 5000

镜像的好处

如果发生媒体错误,镜像会向数据库服务器管理员提供了一种无需让数据库服务器离线即可恢复数据的方式。此功能带来了更高的可靠性和更少的系统宕机时间。而且,应用程序可继续从其主要块区位于受影响媒介的数据库中读取和写入数据,只要镜像此数据的块区位于不同的媒介上。

镜像的成本

镜像会产生磁盘空间和性能成本。磁盘空间成本源于存储镜像数据所需的额外的空间。性能成本源于同时向主要和镜像块区执行写入。使用多个虚拟处理器来执行磁盘写入可减少这一性能成本。使用拆分读取 (split read) 可实际地改善只读数据的性能。对于拆分读取,数据库服务器要么从主要块区读取数据,要么从镜像块区读取,具体取决于数据在块区中的位置。

恢复

当数据库服务器恢复镜像块区时,它会执行镜像开始时使用的相同恢复过程。镜像恢复过程包含将数据从现有的在线块区复制到新的、经过修复的块区上,直到两个块区相同。

当开始恢复时,数据库服务器将禁用的块区设置为恢复模式,并将信息从在线块区复制到恢复块区。当恢复完成时,块区自动恢复在线状态。无论是恢复镜像配对的主要块区,还是恢复镜像块区,都可以执行相同的恢复步骤。

使用数据跳过功能

碎片提供的一个好处是,在 I/O 操作期间能够跳过不可用的表碎片。例如,甚至在一个碎片位于一个目前由于磁盘故障而不可用的块区上时,查询也可以继续执行。当发生此情形时,磁盘故障只会影响碎片表中的部分数据。相反,没有碎片化的表如果位于发生故障的磁盘上,它们可能变得完全无法访问。

要启用数据跳过功能,可执行以下步骤。

  1. 在语句 DATASKIP ON dbspace_list 中将 DATASKIP 参数设置为 OFF、ALL 或 ON。OFF 表示数据库服务器不会跳过任何碎片。如果一个碎片不可用,查询会返回一个错误。ALL 表示会跳过任何不可用的碎片。ON dbspace_list 告诉数据库服务器跳过位于指定 dbspace 中的任何碎片。
  2. 将 SET DATASKIP 参数设置为 ON,使用 SET DATASKIP ON dbspace1, dbspace5 指定跳过的碎片。此语句只要在应用程序尝试访问一个 dbspace 并且数据库服务器发现 dbspace 不可用时,数据库服务器就会跳过 dbspace1 或 dbspace5。如果数据库服务器发现 dbspace1 和 dbspace5 都不可用,它将跳过两个 dbspace。

SET DATASKIP 语句的 DEFAULT 设置使数据库服务器管理员能够控制 dataskip 功能,如 清单 12 中所示。

清单 12. 设置 dataskip 语句
SET DATASKIP DEFAULT

使用 RAW 表

RAW 表是无日志记录的永久表,类似于无日志记录数据库中的表。RAW 表具有以下特征。

  • 支持 RAW 表中的行的更新、插入和删除操作,但这些操作不会记录在日志中。
  • 您可以在 RAW 表上定义索引,但它们不支持主键约束或惟一约束。
  • 不支持使用轻量附加来加载 RAW 表,除了在高性能加载器 (HPL) 操作和在指定 INTO TEMP ... WITH NO LOG 的查询中。
  • 无论存储在有日志记录的数据库还是无日志记录的数据库中,RAW 表都具有相同的属性。
  • 如果更新一个 RAW 表,除非在更新后执行 0 级备份,否则将无法可靠地还原数据。如果该表自这次备份后没有更新过,则可以从上一个物理备份还原该 RAW 表,但仅备份逻辑日志不足以保证 RAW 表可恢复。
  • 快速恢复可回滚 STANDARD 表上的不完整事务,但不能回滚 RAW 表上的事务。

RAW 表用于数据的初始加载和验证。要加载 RAW 表,可以使用任何加载实用程序,包括 dbexport 或表达模式中的 HPL。如果在加载 RAW 表时发生了错误或故障,得到的数据将是发生故障时磁盘上的数据。

注意:

  • 不要在事务中使用 RAW 表。加载数据后,使用 ALTER TABLE 语句将表更改为 STANDARD 类型并执行一次 0 级备份,然后才能在事务中使用该表。
  • 不要在 RAW 或 TEMP 表上使用企业复制。在高可用性集群环境中使用 RAW 表时存在一些限制。因为对 RAW 表进行的修改未记入日志,而且因为辅助服务器(包括 HDR、RSS 和 SDS)使用日志记录来与主要服务器保持同步,所以您不能在 RAW 表上执行以下操作:
    • 在主要服务器上,可以创建、丢弃和访问 RAW 表;但是,将表模式从不记入日志更改为记入日志,或者从记入日志更改为不记入日志是不允许的。在高可用性集群环境中更改表的模式会得到错误代码 19845
    • 在辅助服务器(HDR、SDS 或 RSS)上,不能访问 RAW 表来执行任何操作。尝试从 SQL 访问 RAW 表会得到错误代码 19846

清单 13 给出了创建一个 RAW 表的代码。

清单 13. 创建一个 RAW 表
create raw table t1 (col1 char(8));

理解表碎片和数据存储

碎片功能为您提供了对数据库在何处存储数据的更多控制权。不限制您指定各个表和索引的位置。您还可以指定表和索引碎片的位置,它们是一个表或位于不同存储空间索引的某部分。您可以将 dbspace 或 sbspace 碎片化。

通常,表碎片化会在最初创建表时执行。清单 14 给出了两个 CREATE TABLE 语句的示例。

清单 14. 创建一个表
CREATE TABLE tablename ... FRAGMENT BY ROUND ROBIN IN 
dbspace1, dbspace2, dbspace3; 

CREATE TABLE tablename ...FRAGMENT BY EXPRESSION 
<Expression 1> in dbspace1, 
<Expression 2> in dbspace2, 
<Expression 3> in dbspace3;

FRAGMENT BY ROUND ROBIN 和 FRAGMENT BY EXPRESSION 关键字表示两个不同的分发模式。两个语句都将碎片与 dbspace 关联。

当碎片化一个表时,您也可以在同一个 dbspace 中创建该表的多个分区,如 清单 15 中所示。

清单 15. 在同一个 dbspace 中创建多个分区的示例
CREATE TABLE tb1(a int) 
        FRAGMENT BY EXPRESSION 
                PARTITION part1 (a >=0 AND a < 5) in dbs1, 
                PARTITION part2 (a >=5 AND a < 10) in dbs1 
                ... 
             ;

图 2 演示了碎片在指定数据位置过程中的作用。

图 2. 将存储的逻辑单元(包括表碎片)和物理单元相链接的 dbspace
该 dbspace 将存储的逻辑单元(包括表碎片)和物理单元相链接

配置自动空间管理

只要需要更多空间,IBM Informix 就会自动添加更多存储空间,以避免空间不足错误和减少在存储空间不足时所需的监视时间。自动空间管理功能允许 IBM Informix 服务器自动添加空间,或者您可以手动扩展一个空间或扩展一个块区。

要在服务器上配置自动空间管理,可设置 onconfig 参数 SP_AUTOEXPAND、SP_THRESHOLD 和 SP_WAITTIME。然后创建一个存储池,其中包含服务器用于扩展一个存储空间(dbspace、临时 dbspace、sbspace临时 sbspace 或 blobspace)的可用存储空间的实体(原始设备、熟文件和目录)。

当服务器扩展一个存储空间时,服务器可向存储空间添加一个块区。如果存储空间是个没有镜像的 dbspace 或临时 dbspace,服务器也可以扩展存储空间中的块区。

使用 ONCONFIG 参数

要使服务器能够自动向可用的存储空间添加空间,可按 表 1 中所示配置 ONCONFIG 参数。

表 1. 自动空间管理配置参数
参数描述
SP_AUTOEXPAND启用或禁用块区的自动创建或扩展
SP_THRESHOLD定义在服务器自动运行一个任务来扩展一个存储空间(通过扩展空间中的一个现有块区或添加一个新块区)之前,在存储空间中可存在的最小 KB 数。
SP_WAITTIME指定在返回空间不足错误之前,一个线程等待一个 dbspace、临时 dbspace、sbspace、临时 sbspace 或 blobspace 空间执行扩展的最大秒数。

理解存储池

每个 IBM Informix 数据库都有一个存储池。该存储池包含了服务器需要自动扩展一个现有的 dbspace、临时 dbspace、sbspace、临时 sbspace 或 blobspace 时能够使用的目录、熟文件和原始设备的相关信息。

当存储空间到达 SP_THRESHOLD 配置参数中定义的一个阈值之下时,IBM Informix 可自动运行扩展空间(通过扩展空间中的一个现有块区或添加一个新块区)的任务。

您可以使用 SQL 管理 API 命令执行以下任何操作:

  • 添加、删除或修改描述存储池中的一个目录、熟文件或原始设备的条目。服务器在必要时可使用存储池条目中指定的信息来向自动现有的存储空间添加空间。
  • 通过修改与扩展一个存储空间相关联的两个 dbspace 的不同大小,控制如何使用一个存储池条目。
  • 将一个块区标记为可扩展或不可扩展。
  • 在您不希望 IBM Informix 自动扩展空间时直接扩展空间的大小。
  • 立即将一个块区的大小扩展为指定的最小量。
  • 从存储池中的一个条目创建一个存储空间或块区。
  • 将丢弃的存储空间或块区中的空闲空间返回到存储池。

sysadmin 数据库中的存储池表包含有关 IBM Informix 服务器中一个存储池的所有条目的信息。

当存储池包含条目时,您也可以运行 SQL 管理 API 命令来手动执行以下任务:

  • 在不希望等待运行自动扩展空间的任务时,扩展存储空间或扩展块区。
  • 从存储池条目创建存储空间或将空存储空间中的空间返回到存储池。

作为运行 SQL 管理 API 命令的替代方法,您可以使用 OpenAdmin Tool (OAT) 作为一个图形界面来配置自动和手动空间管理,并管理存储池条目。

管理存储池条目

admin() 或 task() 函数指定一组参数和一个管理存储池的函数。表 2 描述了每个函数的参数。

表 2. SQL admin() 或 task() 函数用于管理存储池条目的参数
参数描述示例
storagepool add创建一个存储池条目
EXECUTE FUNCTION task("storagepool add", "path", 
        "begin_offset", "total_size", "chunk size",priority");
storagepool modify修改一个存储池条目
EXECUTE FUNCTION task("storagepool modify", "storage_pool_entry_id", 
"new_total_size","new_chunk size", "new_priority");
storagepool delete删除一个存储池条目
EXECUTE FUNCTION task("storagepool delete", "storage_pool_entry_id");
storagepool purge all删除所有存储池条目
EXECUTE FUNCTION task("storagepool purge all");
storagepool purge full删除所有装满的存储池条目
EXECUTE FUNCTION task("storagepool purge full");
storagepool purge errors删除具有错误的存储池条目
EXECUTE FUNCTION task("storagepool purge errors");

存储池大小和偏移的默认单位为 KB。但是,您可以使用以下任何方式指定信息:

  • "100000"
  • "100000 K"
  • "100 MB"
  • "100 GB"
  • "100 TB"

清单 16 展示了如何添加一个新的存储池条目,其中的空间为一个名为 /inst/dbspaces 的目录,具有偏移起始值 0、总大小 0、一个大小为 50 MB 的初始块区和一个高优先级。

清单 16. 添加一个新存储池条目的示例
EXECUTE FUNCTION task("storagepool add", "/inst/dbspaces", "0", "0", "50000","1");

在此示例中,偏移 0 和总大小 0 是一个目录惟一可接受的条目。

清单 17展示了如何将存储池条目 8 的总大小、块区大小和优先级更改为 10 GB、10 MB 和中等优先级。

清单 17. 更改属性的示例
EXECUTE FUNCTION task("storagepool modify", "8", "10 GB", "10000", "2");

清单 18展示了如何删除条目 ID 为 7 的存储池条目。

清单 18. 删除一个存储池条目的示例
EXECUTE FUNCTION task("storagepool delete", "7");

创建可扩展块区

可扩展块区是在一个应用程序需要额外的存储空间时 IBM Informix 可自动扩展或您可以手动扩展的块区。如果您拥有可扩展块区,则无需添加新块区或花时间尝试确定哪个存储空间将耗尽空间或它何时会耗尽空间。将 IBM Informix 配置为自动添加更多存储空间,可以避免在一个分区需要额外存储空间并无法在该分区所在的空间内找到一个块区时发生错误。

可扩展块区必须是一个未镜像的 dbspace 或临时 dbspace。

您可以使用 SQL 管理 API 命令和 modify space sp_sizes 参数,使用 清单 19 中的语法修改您可扩展块区所在的空间的扩展大小和创建大小。

清单 19. 修改扩展大小
EXECUTE FUNCTION task("modify space sp_sizes","space_name",
                      "new_create_size","new_extend_size");

清单 20将 dbspace3 的最小创建大小设置为 60 MB,将最小扩展大小设置为 10 MB。

清单 20. 设置最小创建大小
EXECUTE FUNCTION task("modify space sp_sizes", "dbspace3", "60000","10000");

清单 21 将 dbspace8 的最小创建大小设置为 20%,将最小扩展大小设置为 1.5%。

清单 21. 设置最小创建大小和最小扩展大小
EXECUTE FUNCTION task("modify space sp_sizes", "dbspace8", "20","1.5");

将块区标记为可扩展或不可扩展

将块区标记为可扩展,即可启用块区的自动或手动扩展。可以将该标记更改为不可扩展来预防块区的自动或手动扩展。如果一个块区标记为不可扩展,在块区中只有很少或没有空闲空间时,服务器将无法自动扩展该块区。(但是,如果存储池包含条目,服务器可通过向存储空间添加另一个块区来扩展该存储空间。)另外,如果一个块区标记为不可扩展,将无法手动扩展该块区的大小。

可扩展块区必须位于一个没有镜像的 dbspace 或临时 dbspace 中。

要将块区标记为可扩展,可运行带 modify chunk extendable 参数的 admin() 或 task() 函数,如 清单 22 中所示。

清单 22. 启用 modify chunk extendable 参数
EXECUTE FUNCTION task("modify chunk extendable", "chunk number");

要将块区标记为不可扩展,可运行带 modify chunk extendable off 参数的 admin() 或 task() 函数,如 清单 23 中所示。

清单 23. 禁用 modify chunk extendable 参数
EXECUTE FUNCTION task("modify chunk extendable off", "chunk number");

清单 24指定可扩展块区 12。

清单 24. 扩展块区 12
EXECUTE FUNCTION task("modify chunk extendable", "12");

更改自动添加更多空间的阈值和等待时间

尽管 IBM Informix 可通过在一个存储空间完全装满时自动扩展或添加块区,以应对空间不足的情况,但您也可以将服务器配置为在存储空间完全装满之前扩展或添加块区。

指定一个 dbspace、临时 dbspace、sbspace、临时 sbspace 或 blobspace 中的最少空间 KB 量的阈值。您定义的阈值会触发扩展空间的任务。

也可以使用 SP_WAITTIME 配置参数指定在返回空间不足错误之前线程等待空间扩展的最大秒数。

要更改阈值和等待时间,可执行以下一个步骤:

  • 将 SP_THRESHOLD 配置参数中指定的阈值从 0(禁用)更改为非 0 值。执行一个介于 1 和 50 之间的值来表示一个从 1000 到块区最大大小(以 KB 为单位)的百分比。
  • 更改 SP_WAITTIME 配置参数的值,它指定在返回空间不足错误之前,一个线程等待空间扩展的最大秒数。

配置监视空间不足任务的频率

您可以更改 sysadmin 数据库中定义的 mon_low_storage 任务的频率,该任务会定期扫描在 SP_THRESHOLD 配置参数指定的阈值之下的 dbspace 列表。如果该任务找到在该阈值之下的空间,它会尝试通过扩展一个扩扩展块区或使用存储池来添加块区来扩展该空间。

mon_low_storage 任务的默认频率为每小时一次,但可以将该任务配置为更频繁或更不频繁地运行。

要将 mon_low_storage 任务配置为更频繁或更不频繁地运行,可运行 清单 25 中的 SQL 语句,其中的分钟为每次运行之间间隔的分钟数。

清单 25. 配置 mon_low_storage
DATABASE sysadmin; UPDATE ph_task set tk_frequency = INTERVAL (minutes) MINUTE TO MINUTE 

WHERE tk_name = "mon_low_storage";

例如,要将任务配置为每 10 分钟运行一次,可运行 清单 26 中的 SQL 语句。

清单 26. 每 10 分钟运行一次 mon_low_storage
DATABASE sysadmin; UPDATE ph_task set tk_frequency = INTERVAL (10) MINUTE TO MINUTE 
WHERE tk_name = "mon_low_storage";

手动扩展空间或扩展可扩展块区

您可以在必要时手动扩展一个空间或扩展一个块区,而不用等待 IBM Informix 自动扩展该空间或扩展一个块区。

开始之前,请记住:

  • 只有在块区位于一个未镜像的 dbspace 或临时 dbspace 中时,才可扩展该块区。
  • 块区必须首先标记为可扩展,它才能扩展。如果未标记,必须运行带 modify chunk extendable 参数的 admin() 或 task() 函数来将该块区指定为可扩展。
  • 如果一个空间不能通过扩展块区来扩展,存储池必须包含可供服务器用于创建新块区的有效条目。

要直接增加存储空间,可使用以下一种方法:

  • 通过运行带 modify space expand 参数的 admin() 或 task() 函数来手动扩展一个空间,如 清单 27 中所示。
    清单 27. 使用 modify space expand 参数
    EXECUTE FUNCTION task("modify space expand", "space_name","size");

    例如,清单 28 将编号为 8 的空间扩大 1 GB。

    清单 28. 将空间 8 扩大 1 GB
    EXECUTE FUNCTION task("modify space expand", "8", "1000000");

    服务器通过扩展空间中的一个块区或添加一个新块区来扩展空间。服务器可依据存储空间的页面大小以及扩展期间每个存储池条目使用的已配置块区大小,将请求的大小舍入为整数。

  • 运行带 modify chunk extend 参数的 admin() 或 task() 函数来手动扩展一个块区,如 清单 29 中所示。
    清单 29. 使用 modify chunk extend 参数
    EXECUTE FUNCTION task("modify chunk extend", "chunk_number","extend_amount");

    例如,清单 30将编号为 12 的块区扩大 5000 KB。

    清单 30. 将块区 12 扩大 5000 KB
    EXECUTE FUNCTION task("modify chunk extend", "12", "5000");

    服务器可依据存储空间的页面大小将请求的大小舍入为整数。

理解 storagepool 表

sysadmin 数据库中的 storagepool 表包含一个 IBM Informix 实例中存储池中的所有条目信息。每个条目表示服务器在自动扩展一个存储空间时可使用的空闲空间。


理解碎片

碎片是一种数据库服务器功能,它允许您在表级别上控制将数据存储在何处。碎片支持您依据某种算法或模式定义一个表中的行、智慧大对象和索引键分组。

用于将行或索引键分组到碎片中的模式称为分布模式。分配模式和您用于放置碎片的一组 dbspace 一起构成了碎片战略。决定是否将行、索引键或两者都碎片化,并决定应如何在碎片上分布行或键之后,您可以决定一种模式来实现此分布。

当创建碎片表和索引时,数据库服务器将每个表和索引碎片的位置以及其他相关信息存储在名为 sysfragments 的系统目录表中。您可以使用此表访问有关碎片表和索引的信息。如果使用一个用户定义的例程作为碎片表达式的一部分,该信息会记录在 sysfragexprudrdep。

从一个最终用户或客户端应用程序的角度看,碎片表等同于一个没有碎片化的表。客户端应用程序不需要任何修改,即可访问碎片表中的数据。

如果您的目标是改进至少以下一个方面,可以考虑将您的表碎片化:

  • 单用户响应时间
  • 并发性
  • 可用性
  • 备份和还原特征
  • 数据加载

碎片表可属于一个具有日志记录的数据库或没有日志记录的数据库。与未碎片化的表一样,如果碎片表是一个没有日志记录的数据库,在发生故障时可能出现数据不一致性。

探索表碎片的分布模式

分布模式是数据库服务器用于在碎片上分布行或索引条目的一种方法。IBM Informix 数据库服务器支持以下分布模式:

  • 基于表达式
  • 基于表达式的范围规则
  • 基于表达式的任意规则
  • MOD 函数
  • 插入和更新行
  • Round-robin

基于表达式

此分布模式将包含指定值的行放在同一个碎片中。您可以指定一个碎片表达式来定义向每个碎片分配一组行的条件,作为一个范围规则或某种任意的规则。您可以指定一个剩余碎片来持有与任何其他碎片条件不匹配的所有行,但剩余碎片会降低基于表达式的分布模式的效率。

要指定一种基于表达式的分布模式,可使用 CREATE TABLE 或 CREATE INDEX To 语句的 FRAGMENT BY EXPRESSION 子句,如 清单 31 中所示。

清单 31. 使用 FRAGMENT BY EXPRESSION 子句的示例
CREATE TABLE accounts (id_num INT, name char(15))
FRAGMENT BY EXPRESSION 
Id_num <= 100 IN dbspace_1, 
id_num < 100 AND id_num <= 200 IN dbspace_2,
Id_num > 200 IN dbspace_3

当使用 CREATE TABLE 语句的 FRAGMENT BY EXPRESSION 子句来创建碎片表时,必须为您创建的表的每个碎片提供一个条件。

可以定义范围规则或任意规则来向数据库服务器表明如何将行分布到碎片上。

基于表达式的范围规则

范围规则使用 SQL 关系和逻辑运算符来定义一个表中每个碎片的边界。范围规则可包含以下有限的运算符:

  • 关系运算符 >、<、>=、<=
  • 逻辑运算符 AND 和 OR
  • 代数表达式,包括内置的函数

范围规则可以基于一个简单的代数表达式,如 清单 32 中所示。在此示例中,表达式是对于一个列的简单引用。

清单 32. 使用 FRAGMENT BY EXPRESSION 子句和范围规则的示例
FRAGMENT BY EXPRESSION
id_num > 0 AND id_num <= 20 IN dbsp1,
id_num > 20 AND id_num <= 40 IN dbsp2,
Id_num > 40 IN dbsp3

可对多个代数表达式进行结合或分离来形成范围规则中的表达式。清单 33 展示了两个用于定义两组范围的代数表达式。第一组范围基于代数表达式 YEAR(Died) - YEAR(Born)。第二组范围基于 MONTH(Born)

清单 33. 展示用于定义两组范围的两个代数表达式示例
FRAGMENT BY EXPRESSION YEAR
(Died) - YEAR(Born) < 21 AND MONTH(Born) >= 1 AND MONTH(Born) < 4 IN dbsp1,
YEAR(Died) - YEAR(Born) < 40 AND MONTH(Born) >= 4 AND MONTH(Born) < 7 IN dbsp2,

基于表达式的任意规则

任意规则使用 SQL 关系和逻辑运算符。不同于范围规则,任意规则允许您使用任何关系运算符和任何逻辑运算符来定义规则。此外,可以在规则中引用任何多个表列。任意规则通常包含使用 OR 逻辑运算符来分组数据,如 清单 34 中所示。

清单 34. 展示在范围中使用 OR 逻辑运算符来分组数据的示例
FRAGMENT BY EXPRESSION 
zip_num = 95228 OR zip_num = 95443 IN dbsp2,
zip_num = 91120 OR zip_num = 92310 IN dbsp4, 
REMAINDER IN dbsp5

MOD 函数

您可以在 FRAGMENT BY EXPRESSION 子句中使用 MOD 函数来将一个表中的每一行映射到一组整数(哈希值)中。数据库服务器使用这些值来确定它将给定行存储在哪个碎片中。清单 35 展示了如何在基于表达式的分布模式中使用 MOD 函数。

清单 35. 展示 MOD 函数的使用示例
FRAGMENT BY EXPRESSION 
MOD(id_num, 3) = 0 IN dbsp1,
MOD(id_num, 3) = 1 IN dbsp2,
MOD(id_num, 3) = 2 IN dbsp3

插入和更新行

当插入或更新一行时,数据库服务器会按照指定的顺序评估碎片表达式,以查看该行是否属于任何碎片。如果是,数据库服务器会在一个碎片中插入或更新该行。如果该行不属于任何碎片,那么会将该行放在剩余子句所指定的碎片中。如果分布模式不包含一个剩余子句,以及如果该行与任何现有碎片表达式的条件都不匹配,那么数据库服务器会返回一个错误。

Round-robin

此分布模式将行依次放在碎片中,循环这一系列碎片,以均匀地分布行。数据库服务器在内部定义具体规则。

对于 INSERT 语句,数据库服务器在一个随机数上使用一个哈希函数来确定将该行放在哪个碎片中。对于 INSERT 游标,数据库服务器将第一行放在一个随机碎片中,将第二行放在下一个顺序碎片中,依此类推。如果一个碎片已装满,它将被跳过。

要指定一种 round-robin 分布模式,可使用 CREATE TABLE 语句的 FRAGMENT BY ROUND ROBIN 子句。清单 36 给出了一个具有 round-robin 分布模式的碎片表。

清单 36. 一种 round-robin 分布模式
CREATE TABLE account_2 
        ...
        ... 
FRAGMENT BY ROUND ROBIN IN dbspace1, dbspace2, dbspace3

当数据库服务器接收到将一些行插入到一个使用 round-robin 分布模式的表中的请求时,它将以使每个碎片中的行数大体相等的方式来分布行。round-robin 分布也称为均匀分布,因为信息均匀地分布在碎片中。将行分布到使用 round-robin 分布表的规则仅适用于数据库服务器内部。

注意:只能将 round-robin 分布模式用于表碎片。不能将使用此分布模式的索引碎片化。

创建一个碎片表

为表碎片确定了合适的分布模式后,可在创建该表的同时将它碎片化,或者可以碎片化现有的未碎片化的表。

要创建碎片表,可使用 CREATE TABLE 语句的 FRAGMENT BY 子句。清单 37 展示了如何创建一个类似于 stores_demo 数据库中的 orders 表的碎片表。该示例为 3 个碎片使用了 round-robin 分布模式。请咨询您的数据库服务器管理员来设置 3 个 dbspace:分别用于 3 个碎片 dbspace1、dbspace2 和 dbspace3。

清单 37. 展示创建碎片表的示例
CREATE TABLE my_orders ( 
        order_num     SERIAL(1001), 
        order_date    DATE,
        customer_num  INT,
        ship_instruct CHAR(40),
        backlog       CHAR(1),
        po_num        CHAR(10),
        ship_date     DATE,
        ship_weight   DECIMAL(8,2),
        ship_charge   MONEY(6),
        paid_date     DATE,
        PRIMARY KEY (order_num),
        FOREIGN KEY (customer_num) REFERENCES customer(customer_num))
        FRAGMENT BY ROUND ROBIN IN dbspace1, dbspace2, dbspace3

清单 38 展示了如何使用基于表达式的碎片来创建同一个表。

清单 38. 使用基于表达式的碎片创建碎片表的示例
CREATE TABLE my_orders (order_num SERIAL, ...) 
FRAGMENT BY EXPRESSION 
        order_num < 10000 IN dbspace1, 
                order_num >= 10000 and order_num < 20000 IN dbspace2, 
                order_num >= 20000 IN dbspace3

从未碎片化的表创建碎片表

在以下环境中,您可能需要将未碎片化的表转换为碎片表:

  • 您拥有表碎片的一个应用程序实现的版本。
  • 您希望将多个小表转换为一个较大的碎片表。
  • 您有一个您希望碎片化的现有大表。

请记住,在执行转换之前,您必须设置适当数量的 dbspace 来包含新创建的碎片表。

创建多个未碎片化的表

您可以将两个或多个未碎片化的表组合为一个碎片表。这些未碎片化的表必须具有相同的表结构,必须存储在独立的 dbspace 中。要组合未碎片化的表,可使用 ALTER FRAGMENT 语句的 ATTACH 子句。

例如,假设您有 3 个未碎片化的表 account1、account2 和 account3,并且您将这些表分别存储在 dbspaces dbspace1、dbspace2 和 dbspace3 中。所有这 3 个表具有相同的结构,并且您希望将它们组合为一个由共同列 acc_num 上表达式进行碎片化的表。您希望其 acc_num 小于或等于 1120 的行存储在 dbspace1 中。acc_num 大于 1120 但小于或等于 2000 的行存储在 dbspace2 中。最后,acc_num 大于 2000 的行存储在 dbspace3 中。清单 39 展示了如何编写此代码。

清单 39. 使用碎片战略碎片化表
ALTER FRAGMENT ON TABLE tab1 ATTACH 
tab1 AS acc_num <=1120, 
tab2 AS acc_num > 1120 and acc_num <= 2000, 
tab3 AS acc_num > 2000;

结果是一个 tab1 表。其他的 tab2 和 tab3 表已不存在。

使用单个未碎片化的表

要从一个未碎片化的表创建一个碎片表,使用 ALTER FRAGMENT 语句的 INIT 子句。例如,假设您希望通过 round-robin 将表 orders 转换为一个碎片表。清单 40 中的 SQL 语句执行了这一转换。

清单 40. 转换表顺序
ALTER FRAGMENT ON TABLE orders INIT 
        FRAGMENT BY ROUND ROBIN IN dbspace1, dbspace2, dbspace3;

未碎片化的表上的任何现有索引将使用与该表相同的碎片战略来进行碎片化。

碎片表中的 rowid

术语 rowid 是一个整数,定义一行的物理位置。未碎片化表中一个行中的 rowid 是一个惟一且固定的值。相反,碎片表中的行没有分配 rowid。

注意:使用主键作为应用程序中的方法访问,而不使用 rowid。因为主键在 SQL 的 ANSI 规范中定义,所以使用主键访问数据会使您的应用程序更具可移植性。

要适应必须为碎片表引用 rowid 的应用程序,您可以为碎片表显式创建一个 rowid 列。但是,不能为类型化的表使用 WITH ROWIDS 子句。

要创建 rowid 列,使用下列任一 SQL 语法:

  • CREATE TABLE 语句的 WITH ROWIDS 子句t
  • ALTER TABLE 语句的 ADD ROWIDS 子句
  • ALTER FRAGMENT 语句的 INIT 子句

当创建 rowid 列时,数据库服务器会采取以下操作:

  • 向表中的每行添加一个 4 字节的惟一值
  • 创建一个内部索引,供它用于按 rowid 访问表中的数据
  • 在 sysfragments 系统目录表中为内部索引插入一行

碎片化智慧大对象

您可以在 CREATE TABLE 语句的 PUT 子句中指定多个 sbspace,以在一列上实现智慧大对象的 round-robin 碎片化。如果为一个 CLOB 或 BLOB 列指定多个 sbspace,数据库服务器会以 round-robin 方式将该列的智慧大对象分配给指定的 sbspace。有了以下 CREATE TABLE 语句,数据库服务器可将以 round-robin 方式将大对象从 cat_photo 列分配给 sbcat1、sbcat2 和 sbcat3。清单 41 给出了代码。

清单 41. 一个列上智慧大对象的 Round-robin 碎片化
CREATE TABLE catalog ( 
        catalog_num  SERIAL, 
        stock_num    SMALLINT,
        manu_code    CHAR(3),
        cat_descr    LVARCHAR,
        cat_photo    BLOB) 
PUT cat_photo in (sbcat1,sbcat2, sbcat3);

修改碎片战略

您可以对碎片表执行两种一般类型的修改。第一种类型包含可对未碎片化的表执行的修改。这些修改包括添加列、丢弃列、更改列数据类型等。对于这些修改,可使用您通常会在未碎片化表上使用的 ALTER TABLE 语句。第二种修改类型包含对碎片战略的更改。

有时,您需要在实现碎片后修改碎片战略。最常见的情况是,您在为碎片使用查询内或查询间并行化时,需要修改碎片战略。在这些环境中修改碎片战略是改善数据库服务器系统性能的多种方式中的一种。请参阅下一节,了解修改碎片战略的详细信息。

重新初始化碎片战略

您可以使用 ALTER FRAGMENT 语句的 INIT 子句来在未碎片化的表上定义和初始化一条新碎片战略。您也可以使用 INIT 子句更改碎片表达式的计算顺序。

清单 42 展示了如何使用 INIT 子句来完全重新初始化碎片战略。

清单 42. 碎片表的初始创建
CREATE TABLE account (acc_num INTEGER, ...) 
    FRAGMENT BY EXPRESSION 
        acc_num <= 1120 in dbspace1,
        acc_num > 1120 and acc_num < 2000 in dbspace2,
        REMAINDER IN dbspace3;

假设在使用此分布模式几个月后,您发现 dbspace2 中包含的碎片中的行数是其他碎片所包含的行数的两倍。这种失衡导致包含 dbspace2 的磁盘成为了 I/O 瓶颈。

为了修复此情形,您决定修改分布,使每个碎片中的行数大体均衡。您希望修改分布模式,使它包含 4 个碎片,而不是 3 个碎片。一个新 dbspace dbspace2a 中包含的碎片存储以前包含在 dbspace2 中的前半部分的行。dbspace2 中的碎片存储它以前存储的后半部分的行。

要实现新分布模式,首先创建 dbspace dbspace2a,然后使用 清单 43 中的代码。

清单 43. 实现一种新分布模式
ALTER FRAGMENT ON TABLE account INIT 
     FRAGMENT BY EXPRESSION 
        acc_num <= 1120 in dbspace1,
        acc_num > 1120 and acc_num <= 1500 in dbspace2a,
        acc_num > 1500 and acc_num < 2000 in dbspace2, 
        REMAINDER IN dbspace3;

只要执行此语句,数据库服务器会立即放弃旧的碎片战略,该表包含的行会依据新碎片战略重新分布。

您也可以使用 ALTER FRAGMENT 语句的 INIT 子句执行以下操作:

  • 将一个未碎片化的行转换为碎片表
  • 将一个碎片表转换为未碎片化的表
  • 将一个使用任何战略碎片化的表转换为任何其他碎片战略

修改碎片战略

您可以使用 ADD、DROP 和 MODIFY 子句更改一个表或索引上的碎片战略。

ADD 子句

当定义一种碎片战略时,您可能需要添加一个或更多碎片。可以使用 ALTER FRAGMENT 语句的 ADD 子句向一个表添加一个新碎片。假设您希望体向您使用 清单 44 中语句所创建的表中添加一个碎片。

清单 44. 添加一个子句
CREATE TABLE sales (acc_num INT, ...) 
     FRAGMENT BY ROUND ROBIN IN dbspace1, dbspace2, dbspace3;

要向表 sales 添加一个新碎片 dbspace4,可使用 清单 45 中的命令。

清单 45. 添加一个新碎片
ALTER FRAGMENT ON TABLE sales ADD dbspace4;

如果碎片战略是基于表达式的,ALTER FRAGMENT 语句的 ADD 子句包含了在现有 dbspace 之前或之后添加一个 dbspace 的选项。

DROP 子句

当定义一种碎片战略时,您可能会丢弃一个或多个碎片。使用 IBM Informix,您可以使用 ALTER FRAGMENT ON TABLE 语句的 DROP 子句丢弃一个表中的碎片。假设您希望从您使用 清单 46 中语句所创建的表中丢弃一个碎片。

清单 46. 丢弃一个碎片
CREATE TABLE sales (col_a INT), ...) 
     FRAGMENT BY ROUND ROBIN IN dbspace1, dbspace2, dbspace3;

ALTER FRAGMENT 语句 清单 47 使用一个 DROP 子句丢弃 sales 表中的第三个碎片 dbspace3。

清单 47. 丢弃第三个碎片
ALTER FRAGMENT ON TABLE sales DROP dbspace3;

当发出此语句时,dbspace3 中的所有行会迁移到剩余的 dbspace:dbspace1 和 dbspace2。

MODIFY 子句

使用带有 MODIFY 子句的 ALTER FRAGMENT 语句修改现有碎片战略中的一个或多个表达式。假设您最初在 清单 48 中创建了一个碎片表。

清单 48. 创建一个碎片表
CREATE TABLE account (acc_num INT, ...) 
     FRAGMENT BY EXPRESSION 
        acc_num <= 1120 IN dbspace1,
        acc_num > 1120 AND acc_num < 2000 IN dbspace2,
        REMAINDER IN dbspace3;

当执行 清单 49 中的 ALTER FRAGMENT 语句时,您要确保没有编号值小于或等于 0 的帐户存储在 dbspace1 所包含的碎片中。

清单 49. 修改碎片示例
ALTER FRAGMENT ON TABLE account MODIFY dbspace1 TO acc_num
           > 0 AND acc_num <= 1120;

不能使用 MODIFY 子句修改您的分布模式所包含的碎片数量。可以使用 ALTER FRAGMENT 语句的 INIT 或 ADD 子句代替。

授予或撤销碎片的权限

如果您希望授予有用的碎片权限,您必须有一种战略来控制数据分布。一种有效的战略是按表达式来将数据记录碎片化。但是,round-robin 数据记录分布战略没有用,因为每个新数据记录都会被添加到下一个碎片中。round-robin 分布会清空任何跟踪数据分布的任何干净方法,进而消除对碎片授权的真正使用。出于基于表达式分布和 round-robin 分布之间的这一区别,GRANT FRAGMENT 和 REVOKE FRAGMENT 语句仅适用于具有基于表达式碎片的表。

当创建碎片表时,不存在默认的碎片授权。使用 GRANT FRAGMENT 语句在一个或多个碎片上授予插入、更新和删除权限。如果希望同时授予所有 3 种权限,可使用 GRANT FRAGMENT 语句的 ALL 关键字。请记住,不能仅通过命名包含碎片的表来授予碎片权限。您必须命名特定的语句。

当您希望撤销插入、更新或删除权限时,可以使用 REVOKE FRAGMENT 语句。此语句会撤销一个或多个用户针对碎片表的一个或多个碎片的权限。如果希望撤销一个表中当前存在的所有权限,可使用 ALL 关键字。如果不在命令中指定任何碎片,撤销的权限将适用于表中当前拥有该权限的所有碎片。

附加或分离碎片

您可以使用 ALTER FRAGMENT ATTACH 和 DETACH 语句来执行碎片操作。ALTER FRAGMENT ATTACH 提供了一种方式来组合两个未碎片化的表或向碎片表中添加碎片。ALTER FRAGMENT DETACH 提供了一种方式来删除一个碎片表的碎片。

ATTACH

使用 ALTER FRAGMENT ON TABLE 语句的 ATTACH 子句来将具有相同结构的表组合到一个碎片战略中。该子句还提供了一种方式,通过利用碎片技术来将大量数据增量地加载到一个现有的表中。

您附加的任何表都必须已在独立的分区中创建。不能多次附加同一个表。ATTACH 子句中列出的所有使用表必须具有与幸存的表相同的结构。列的数量、名称、数据类型和相对位置必须相同。

用户定义的例程以及对一个 ROW 类型列的字段的引用是无效的。不能将一个碎片表附加到另一个碎片表。

所有存储碎片的 dbspace 都必须具有相同的页面大小。

在两个未碎片化的表上执行 ATTACH 操作不能生成一个按间隔或按列表碎片化的幸存表。(如果希望附加两个未碎片化的表,您可使用 ALTER FRAGMENT 语句的 INIT 选项来为一个未碎片化的表定义中间隔或列表碎片模式,然后使用 ATTACH 选项将第二个表附加到它。)

对于按间隔碎片化的幸存表,具有以下限制:

  • 因为数据库服务器确定了碎片的顺序位置,所以 BEFORE 和 AFTER 规范无效。
  • 不能附加其表达式与现有的间隔碎片表达式相匹配的碎片。
  • 在附加超过过渡值的碎片时,正附加碎片的上限必须与一个间隔碎片边界保持一致。也就是说,碎片的上限必须等于过渡值加上间隔值的一个整数倍数。

对于由安全策略保护的碎片表,如果未满足任何以下条件,将一个碎片附加到该表的操作将会失败:

  • 源表和目标包都受相同的安全策略保护。
  • 两个表都具有相同的保护粒度(行级、列级或同时包含行级和列级)。
  • 在两个表中,同一组受保护的列受到了相同安全标签的保护。如果有多个受保护的列,可能每个表中有多个安全标签,但同一个标签必须保护两个表中的同一列。

如果由于未满足一个或多个上述条件,导致 ATTACH 操作失败,可以使用 ALTER TABLE 语句使两个表的模式相等,然后在修改的表上再次执行 FRAGMENT ATTACH 语句。

当将具有相同表结构的表转换为一个表中的碎片时,您允许数据库服务器管理碎片,而不是允许应用程序来管理碎片。分布模式可以是 round-robin 或基于表达式。

要从两个或多个结构相同的未碎片化表中创建一个碎片表,ATTACH 子句必须在附加列表中包含幸存表。附加列表是 ATTACH 子句中的一个表列表。

要在新创建的单个碎片表中包含 rowid 列,可首先附加所有表,然后使用 ALTER TABLE 语句添加 rowid。

将一个表附加到一个碎片表

要将一个未碎片化的表附加到一个已碎片化的表,未碎片化的表必须已在一个独立的 dbspace 中创建,并且必须具有与碎片表相同的表结构。

当将一个或多个表附加到一个碎片表时,consumed_table 必须是未碎片化的。

在 ATTACH 操作中使用 ONLINE 关键字。

ONLINE 关键字要求数据库服务器在内部提交 ALTER FRAGMENT ATTACH 工作(如果没有错误),以及向幸存表应用一个意向独占锁,而不是独占锁。独占锁适用于使用表,这些表必须是未碎片化的表。

执行 ATTACH 后的索引

幸存表上分离的索引会保留相同的碎片战略。也就是说,分离的索引不会自动调整来适应幸存表的新碎片。

在支持事务日志的数据库中,ATTACH 操作会依据幸存表的新碎片战略扩展幸存表上的任何附加索引。使用表的所有行将采用这些自动调整的索引。

在 IBM Informix 的无日志记录的数据库中,ATTACH 操作不会依据幸存表上的新碎片战略来扩展幸存表上的索引。要依据幸存表上的新碎片战略来扩展一个附加索引的碎片战略,必须丢弃该索引并在幸存表上重新创建它。

一些 ALTER FRAGMENT ... ATTACH 操作可能导致数据库服务器更新索引结构。当在这些情况下重新构建一个索引时,关联的列分布会自动重新计算,并且该索引可供查询优化器在为附加了碎片的表设计查询计划时使用。

对于 ALTER FRAGMENT ... ATTACH 自动为其重建了 B 型树索引的一个(或一组)索引列,重新计算的列分布统计信息等同于 HIGH 模式下由 UPDATE STATISTICS 语句所创建的分布。

如果重新构建的索引不是 B 型树索引,自动重新计算的统计信息将对应于 LOW 模式下由 UPDATE STATISTICS 语句所创建的分布。

对 ONLINE ATTACH 操作的需求

只有在幸存表由一种间隔碎片模式来进行碎片化时,您才能在 ALTER FRAGMENT ONLINE ON TABLE 语句上使用 ATTACH 选项。使用表必须是未碎片化的。

幸存表上的所有索引必须具有与该表相同的碎片模式。(也就是说,任何索引都必须附加。)出于此原因,如果该表上有一个主键约束或其他参照约束,建议您首先为该约束创建一个附加索引,然后使用 ALTER TABLE 语句添加该约束。(在默认情况下,系统为主键约束和其他参照约束创建的索引是分离的。)

对于幸存表上的每个索引,在使用表上的同一组列上必须有一个匹配的索引。在 ATTACH 操作期间,使用表上的匹配索引将作为幸存表上的索引碎片而回收。在 ATTACH 操作期间,使用表上的任何其他索引将被丢弃。使用表中将被回收的索引必须是每个都分离在单独的 dbspace 中,而且存储回收索引的 dbspace 必须是存储使用表的相同 dbspace。

如果幸存表上的索引是惟一的,那么使用表上相应的匹配索引也必须是惟一的。

使用表必须具有一种同时满足以下两个条件的检查约束:

  • 它必须准确匹配被附加的碎片表达式。
  • 它必须仅包含一个间隔。

要求使用表中的行在幸存表的范围间隔碎片模式下仅包含一个间隔是预防数据移动的必要需求。包含 ONLINE 关键字的 ALTER FRAGMENT ATTACH 操作中不允许数据移动。

只有使用表可在 ONLINE ATTACH 操作中指定。

清单 50 中的 SQL 语句定义了一个碎片化的 employee 表,该表使用一种范围间隔存储分布模式,在列 emp_id 上具有一个惟一的索引 employee_id_idx(也是碎片键),在列 dept_id 上具有另一个索引 employee_dept_idx。

清单 50. ALTER FRAGMENT ONLINE ATTACH 示例
CREATE TABLE employee (emp_id INTEGER, name CHAR(32),
                dept_id CHAR(2), mgr_id INTEGER, ssn CHAR(12))
        FRAGMENT BY RANGE (emp_id) 
        INTERVAL (100) STORE IN (dbs1, dbs2, dbs3, dbs4) 
                PARTITION p0 VALUES < 200 IN dbs1, 
                PARTITION p1 VALUES < 400 IN dbs2; 
CREATE UNIQUE INDEX employee_id_idx ON employee(emp_id); 
CREATE INDEX employee_dept_idx ON employee(dept_id);

最后两条语句插入了拥有大于过渡碎片上限的碎片键值的行,导致数据库服务器生成两个新的间隔碎片,使最终的碎片列表包含 清单 51 中所示的碎片。

清单 51. 执行 ALTER FRAGMENT ONLINE 之前幸存表中的碎片
p0      VALUES < 200                      - range fragment 
p1      VALUES < 400                      - range fragment (transition fragment) 
sys_p2  VALUES >= 400 AND VALUES < 500 - interval fragment 
sys_p4 VALUES >= 600 AND VALUES < 700  - interval fragment

清单 52 中的 SQL 语句定义了一个未碎片化的 employee2 表,它具有与 employee 表相同的列模式,以及在 employee 表中索引的两个相应列(emp_id 和 dept_id)上的单列索引。这些语句还在列 emp_ssn 上定义了一个惟一的索引 employee2_ssn_idx,在列 name 上定义了另一个索引 employee_dept_idx。所有 4 个索引都存储在 dbspace dbs4 中。CREATE TABLE 语句还指定了一个检查约束 ((emp_id >= 500 AND emp_id <600)),该约束与将附加的使用表碎片表达式精确匹配,并且精确跨越 employee 表的范围间隔碎片模式的单个间隔。

清单 52. 具有相同列模式以及单列索引的示例
CREATE TABLE employee2 
        (emp_id INTEGER, name CHAR(32),
        dept_id CHAR(2), mgr_id INTEGER, ssn CHAR(12),
        CHECK (emp_id >=500 AND emp_id < 600)) in dbs4; 
CREATE UNIQUE INDEX employee2_id_idx ON employee2(emp_id) in dbs4; 
CREATE INDEX employee2_dept_idx ON employee2(dept_id) in dbs4; 
CREATE UNIQUE INDEX employee2_ssn_idx ON employee2(ssn) in dbs4; 
CREATE INDEX employee2_name_idx ON employee2(name) in dbs4;

清单 53 中的语句会返回一个错误,因为附加的碎片是一个范围碎片(一个存储碎片键值低于 employee 表过渡值 400 的行的碎片)。只有间隔碎片可在线附加。

清单 53. 使用范围碎片
ALTER FRAGMENT ONLINE ON TABLE employee ATTACH employee2 AS PARTITION
                    p3 VALUES < 300;

清单 54 中的语句成功运行并创建一个新的 p3 间隔碎片。

清单 54. 创建一个 p3 间隔
ALTER FRAGMENT ONLINE ON TABLE employee ATTACH employee2 AS PARTITION
                    p3 VALUES < 600;

清单 55 给出了运行该语句后的结果。

清单 55. 执行 ALTER FRAGMENT ONLINE 后幸存表中的碎片
p0 VALUES < 200                          - range fragment 
p1 VALUES < 400                          - range fragment 
sys_p2 VALUES >=400 AND VALUES <500   - interval fragment 
sys_p3 VALUES >= 500 AND VALUES < 600 - interval fragment 
sys_p4 VALUES >= 600 AND VALUES < 700 - interval fragment

请注意,清单 55 中成功的 ALTER FRAGMENT ONLINE . . . ATTACH 操作需要定义幸存表和使用表(包括它们的列、索引、约束、索引存储位置和幸存表的间隔碎片战略)的 DDL 语句中的规范之间的多种联系。这些联系如下所示:

  • 使用表上的检查约束仅包含一个间隔。幸存表的间隔值为 100,检查约束为 >= 500 和 < 600。
  • 附加的条件表达式 (< 600) 在内部转换为间隔碎片表达式格式(>= 500 和 < 600),这与检查约束匹配。
  • 附加幸存表上的索引(也就是说,它们使用与该表相同的碎片模式来进行碎片化),因为没有在其 CREATE INDEX 语句中显式指定任何碎片战略。
  • 使用表上的索引被分离到一个 dbspace (dbs4) 中,这是存储使用表的同一个 dbspace。
  • 对于幸存表上的每个索引,使用表上只有一个匹配索引。
  • 使用表上与幸存 employee 表上索引无对应关系的其他索引将在 ONLINE ATTACH 操作期间被丢弃。

DETACH

您可以使用 ALTER FRAGMENT DETACH 语句将一个表碎片从一种分布模式分离出来,并将其内容放在一个新的未碎片化表中。它提供了一种方式来快速删除该表数据的分段。该子句在 ALTER FRAGMENT ON INDEX 语句中无效。

执行 DETACH 子句所生成的新表不会从原始表继承任何索引或约束。只有数据值会得以保留。

类似地,新表不会从原始表继承任何权限。相反,新表拥有任何新表的默认权限。

如果一个表是参照约束的父表,或者如果在该表上定义了一个 rowid 列,DETACH 子句将无法应用于该表。

执行 DETACH 操作后的分布统计信息

附加碎片的一些 ALTER FRAGMENT . . . DETACH 操作可能导致数据库服务器更新索引结构。当在这些情况下重新构建一个索引时,数据库服务器也会重新计算关联的列分布,并且这些统计信息可供查询优化器在为从中分离碎片的表设计查询计划时使用。这些统计信息如下:

  • 对于 ALTER FRAGMENT ... ATTACH 自动为其重建 B 型树索引的一个索引列(或一组列),重新计算的列分布统计信息等同于 HIGH 模式下由 UPDATE STATISTICS 语句所创建的分布。
  • 如果重新构建的索引不是 B 型树索引,自动重新计算的统计信息将对应于 LOW 模式下由 UPDATE STATISTICS 语句所创建的分布。

如果启用了更新分布统计信息的自动模式,并且从中分离的表具有碎片化分布统计信息,数据库服务器会合并分离的碎片统计信息,以形成新的表分布。数据库服务器还会合并剩余碎片的数据分布统计信息,以形成幸存表分布统计信息,并将结果存储在系统目录中。碎片统计信息的重新计算在后台运行。

在 DETACH 操作中使用 ONLINE 关键字

ONLINE 关键字要求数据库服务器在内部提交 ALTER FRAGMENT ... DETACH 工作(如果没有错误),以及向分离碎片的表中应用一个意向独占锁,而不是独占锁。独占锁适用于从分离碎片创建的表。

只能将 ALTER FRAGMENT ONLINE ON TABLE 语句的 DETACH 选项用于使用范围间隔碎片模式的表。

使用范围间隔存储分布模式的表可具有以下两种类型的碎片:

  • 范围碎片,由用户在 CREATE TABLE 或 ALTER TABLE 语句的 FRAGMENT BY 或 PARTITION BY 子句中定义
  • 间隔碎片,如果一行具有超过过渡碎片(最后一个范围碎片)上限的碎片键值,数据库服务器就会在 INSERT 和 UPDATE 操作期间自动生成间隔碎片。

只有间隔碎片可在 ONLINE DETACH 操作中分离。

如果分离的间隔碎片不是最后一个碎片,数据库服务器会修改碎片列表中已分离碎片后任何系统生成的间隔碎片的名称,以与它们在幸存表中的新 sysfragments.evalpos 值匹配。在此碎片重命名操作期间,在使用新分区名称(如果碎片列表中的任何碎片的顺序位置在 ALTER FRAGMENT DETACH 操作期间更改,也会使用这些碎片的新 evalpos 值)更新 sysfragments 系统目录期间,会在碎片上放置一个独占锁。

幸存表上的所有索引必须具有与该表相同的碎片模式。(也就是说,必须附加任何索引。)出于此原因,如果该表上有一个主键约束或其他参照约束,建议您首先为该约束创建一个附加索引,然后使用 ALTER TABLE 语句添加该约束。(默认情况下,系统为主键约束和其他参照约束创建的索引是分离的。)

如果存在访问分离的同一个分区的会话,建议您发出 SET LOCK MODE TO WAIT 语句足够的秒数,以预防非独占访问错误。

清单 56 中的 SQL 语句定义一个碎片化的 employee 表,该表使用一个范围间隔存储分布模式,在列 emp_id 上具有一个惟一索引 employee_id_idx(也是碎片键),在列 dept_id 上具有另一个索引 employee_dept_idx。

清单 56. ALTER FRAGMENT ONLINE ... DETACH 的示例
CREATE TABLE employee (emp_id INTEGER, name CHAR(32), dept_id CHAR(2), 
              mgr_id INTEGER, ssn CHAR(12)) 
        FRAGMENT BY RANGE (emp_id) 
           INTERVAL (100) STORE IN (dbs1, dbs2, dbs3, dbs4) 
              PARTITION p0 VALUES < 200 IN dbs1, 
              PARTITION p1 VALUES < 400 IN dbs2; 
CREATE UNIQUE INDEX employee_id_idx ON employee(emp_id); 
CREATE INDEX employee_dept_idx ON employee(dept_id);

清单 57 中的语句插入具有超过过渡碎片上限的碎片键值的行。

清单 57. 用于 DETACH 语句的值
INSERT INTO employee VALUES (401, "Susan", "DV", 101, "123-45-6789"); 
INSERT INTO employee VALUES (601, "David", "QA", 104, "987-65-4321");

插入的行导致数据库服务器生成两个新的间隔碎片,使得到的碎片列表包含 4 个碎片,如 清单 58 中所示。

清单 58. 执行 ALTER FRAGMENT ONLINE 之前幸存表中的碎片
p0 VALUES < 200                          - range fragment 
p1 VALUES < 400                          - range fragment (transition fragment)
sys_p2 VALUES >= 400 AND VALUES < 500 - interval fragment 
sys_p4 VALUES >= 600 AND VALUES < 700 - interval fragment

清单 59 中的语句返回一个错误,因为要分离的指定碎片是一个范围碎片(一个存储碎片键值低于过渡值 400 的行的碎片)。只有间隔碎片可在线分离。

清单 59. 导致错误的范围碎片
ALTER FRAGMENT ONLINE ON TABLE employee 
DETACH PARTITION p0 employee3;

清单 60 中的语句已成功运行,创建了一个新的 employee3 表来存储分离的碎片中的数据。

清单 60. 成功的间隔碎片 DETACH 操作
ALTER FRAGMENT ONLINE ON TABLE employee 
DETACH PARTITION sys_p2 employee3;

如果存在访问 sys_p2 的并发会话,可以将锁模式设置为 WAIT(设置为足够提交 ONLINE DETACH 操作的秒数),以预防非独占访问错误,如 清单 61 中所示。

清单 61. 设置锁模式
SET LOCK MODE TO WAIT 300; 
ALTER FRAGMENT ONLINE ON TABLE employee DETACH PARTITION sys_p2 employee3;

清单 62 显示了最终的碎片。

清单 62. 执行 ALTER FRAGMENT ONLINE 后幸存表中的碎片
p0 VALUES < 200                         - range fragment 
p1 VALUES < 400                         - range fragment 
sys_p4 VALUES >=600 AND VALUES < 700 - interval fragment

在修改表碎片时强制关闭事务

您可以让服务器强制关闭打开的事务,或在您在日志数据库中发出 ALTER FRAGMENT ON TABLE 操作时在表上放置锁。您可能希望在繁忙的系统(或许是一个一天 24 小时运行的系统)上这么做,并且不希望在修改碎片之前等待会话关闭。

请注意,如果让服务器强制关闭事务,服务器会回滚其他用户的事务。服务器还会在回滚期间通过执行 ALTER FRAGMENT ON TABLE 操作的会话关闭持有游标。

请注意,您必须是用户 informix 或在数据库上具有 DBA 权限,并且该表必须是一个日志数据库。

要在修改表碎片时强制关闭事务,可以执行以下步骤。

  1. 将 SET ENVIRONMENT 语句的 FORCE_DDL_EXEC 环境选项设置为以下值之一:
    • ONon1,以使服务器能够强制关闭打开的事务或在执行 ALTER FRAGMENT ON TABLE 语句时在表上放置一个锁,直到服务器获得一个锁并独占地访问该表。
    • 一个表示秒数的正整数。该数值使服务器能够强制关闭事务,直到服务器获得表上的独占访问和独占锁,或者直到发生指定的时间限制游标。如果服务器无法在指定的时间内强制关闭事务,服务器将停止尝试强制关闭该事务。
    例如,要使 FORCE_DDL_EXEC 环境选项在发出 ALTER FRAGMENT ON TABLE 语句时运行 100 秒,可以指定 SET ENVIRONMENT FORCE_DDL_EXEC '100';
  2. 将锁模式设置为等待,以确保服务器将在强制关闭任何事务之前等待指定的时间量。例如,要将锁模式设置为等待 20 秒,可以指定 SET LOCK MODE TO WAIT 20;
  3. 运行 ALTER FRAGMENT ON TABLE 语句来附加、分离、修改、添加或丢弃碎片。

完成启用了 FORCE_DDL_EXEC 环境选项的 ALTER FRAGMENT ON TABLE 操作后,即可关闭 FORCE_DDL_EXEC 环境选项。例如,指定 SET ENVIRONMENT FORCE_DDL_EXEC 'OFF'

定义一种碎片化索引的战略

当碎片化一个表时,与该表关联的索引会依据您使用的碎片模式而隐式地进行碎片化。您也可以使用 CREATE INDEX 语句的 FRAGMENT BY EXPRESSION 子句来显式碎片化任何表的索引。

碎片表的每个索引占用它具有自己范围的 tblspace。您可以使用与表相同的碎片战略或使用与表不同的碎片战略来碎片化索引。

使用附加索引

附加索引是一种隐式遵循表碎片战略(分布模式和碎片所在的一组 dbspace)的索引。在您第一次碎片化一个表时,数据库服务器会自动创建一个附加索引。

要创建附加索引,不要在 CREATE INDEX 语句中指定碎片战略或存储选项,如 清单 63 中所示。

清单 63. 创建附加索引
CREATE TABLE tb1(a int)
     FRAGMENT BY EXPRESSION 
        (a >=0 AND a < 5) IN dbsbspace1, 
        (a >=5 AND a < 10) IN dbspace2 
        ... 
     ;
...
CREATE INDEX idx1 ON tb1(a);

对于使用基于表达式或 round-robin 分布模式的碎片表,您也可以在一个 dbspace 中创建一个表或索引的多个分区。这可以减少您所需的 dbspace 数量,进而简化 dbspace 的管理。

要创建包含分区的附加索引,可将分区名称包含在 SQL 语句中,如 清单 64 中所示。

清单 64. 包含分区名称
CREATE TABLE tb1(a int) 
     FRAGMENT BY EXPRESSION 
        PARTITION part1 (a >=0 AND a < 5) IN dbs1, 
        PARTITION part2 (a >=5 AND a < 10) IN dbs1 
        ... 
      ; 
...
CREATE INDEX idx1 ON tb1(a);

您可以在 CREATE TABLE、CREATE INDEX 和 ALTER FRAGMENT ON INDEX 语句中使用 PARTITION BY EXPRESSION 代替 FRAGMENT BY EXPRESSION,如 清单 65 中所示。

清单 65. 使用 PARTITION BY EXPRESSION
ALTER FRAGMENT ON INDEX idx1 INIT PARTITION BY EXPRESSION
        PARTITION part1 (a <= 10) IN dbs1, 
        PARTITION part2 (a <= 20) IN dbs1, 
        PARTITION part3 (a <= 30) IN dbs1;

使用 ALTER FRAGMENT 语法将没有分区的碎片索引更改为具有分区的索引。清单 66 中的语法展示了如何将碎片索引转换为包含分区的索引。

清单 66. Using ALTER FRAGMENT syntax
CREATE TABLE t1 (c1 int) FRAGMENT BY EXPRESSION 
        (c1=10) IN dbs1, (c1=20) IN dbs2, (c1=30) IN dbs3 
CREATE INDEX ind1 ON t1 (c1) FRAGMENT BY EXPRESSION 
        (c1=10) IN dbs1, (c1=20) IN dbs2, (c1=30) IN dbs3 
ALTER FRAGMENT ON INDEX ind1 INIT FRAGMENT BY EXPRESSION 
        PARTITION part_1 (c1=10) IN dbs1, PARTITION part_2 (c1=20) IN dbs1, 
        PARTITION part_3 (c1=30) IN dbs1,

创建一个包含分区的表或索引可改善性能,使数据库服务器能够更快地搜索,并且减少了需要的 dbspace 数量。数据库服务器依据与表相同的分布模式来碎片化附加的索引,为索引键使用与表数据相同的规则。因此,附加索引具有以下物理特征:

  • 索引碎片的数量与数据碎片的数量相同。
  • 每个附加索引碎片位于与相应的表数据相同的 dbspace 中,但位于不同的 tblspace 中。
  • 附加索引或未碎片化表上的索引使用 4 字节来表示每个索引条目的行指针。

IBM Informix 不支持树附加索引林。

设计分离索引

分离索引是您使用 CREATE INDEX 语句显式设置的不同碎片战略的索引。清单 67 和 清单 68 中的示例 SQL 语句创建一个分离索引。

清单 67. 创建一个分离索引
CREATE TABLE tb1 (a int) 
     FRAGMENT BY EXPRESSION 
        (a <= 10) IN tabdbspc1, 
        (a <=20) IN tabdbspc2, 
        (a <= 30) IN tabdbspc3;
清单 68. 创建另一个分离索引
CREATE INDEX idx1 ON tb1 (a) 
     FRAGMENT BY EXPRESSION 
        (a <= 10) IN idxdbspc1, 
        (a <= 20) IN idxdbspc2, 
        (a <= 30) IN idxdbspc3;

此示例演示了一种常见的碎片战略:采用与表相同的方式来碎片化索引,但为索引碎片指定不同的 dbspace。将索引碎片放与表不同的 dbspace 中的碎片战略可改善备份、恢复等操作的性能。

默认情况下,CREATE INDEX 语句创建的所有新索引都是分离的,存储在与数据不同的 tablespace 中,除非您指定了弃用的 IN TABLE 语法。

要创建包含分区的分离索引,可将分区名称包含在您的 SQL 语句中,如 清单 69 和 清单 70 中所示。

清单 69. 创建包含分区的分离索引
CREATE TABLE tb1 (a int) 
     FRAGMENT BY EXPRESSION 
        PARTITION part1 (a <=10) IN dbs1, 
        PARTITION part2 (a <= 20) IN dbs2, 
        PARTITION part3 (a <= 30) IN dbs3;
清单 70. 创建包含分区的分离索引
CREATE INDEX idx1 ON tb1 (a) 
     FRAGMENT BY EXPRESSION 
        PARTITION part1 (a <= 10) IN dbs1,
        PARTITION part2 (a <=20) IN dbs2,
        PARTITION part3 (a <= 30) IN dbs3;

您可以在 CREATE TABLE、CREATE INDEX 和 ALTER FRAGMENT ON INDEX 语句中使用 PARTITION BY EXPRESSION 代替 FRAGMENT BY EXPRESSION。

如果不希望碎片化索引,您可以将整个索引放在一个独立的 dbspace 中。

您可以按表达式来碎片化任何表的索引。但是,不能为索引显式创建 round-robin 碎片模式。只要使用 round-robin 碎片模式碎片化一个表,就会将该表附带的所有索引转换为分离索引,以实现最佳的性能。

每个分离索引碎片均位于一个与相应表数据不同的 tblspace 中。因此,数据和索引页不能混合存储在 tblspace 中。

分离索引碎片具有自己的盘区和 tblspace ID。tblspace ID 也称为碎片 ID分区编号。分离索引为每个索引条目使用 8 字节的磁盘空间来保存碎片 ID 和行指针组合。

数据库服务器将每个表和索引碎片的位置,以及其他相关信息存储在系统目录表 sysfragments 中。可以使用 sysfragments 系统目录表来访问与碎片表和索引相关的以下信息:

  • partn 字段中的值是表或索引碎片的分区编号或碎片 ID。分离索引的分区编号不同于相应表碎片的分区编号。
  • strategy 字段中的值是碎片战略中使用的分布模式。

理解碎片表索引上的限制

如果数据库服务器扫描一个碎片索引,则必须扫描多个索引碎片,并且结果必须合并在一起。(一种例外情况是,如果索引是依据某种索引-键范围规则来碎片化的,并且扫描不会跨越一个碎片的边界。)出于此需求,如果索引是碎片化的,索引扫描的性能可能受到影响。

由于这些性能考虑因素,数据库服务器在索引上设置了以下限制:

  • 无法通过 round-robin 来碎片化索引。
  • 无法通过包含不在索引键中的列的表达式来碎片化惟一的索引。

例如,清单 71 中的语句是无效的。

清单 71. 无效的 SQL 语句
CREATE UNIQUE INDEX ia on tab1(col1) 
     FRAGMENT BY EXPRESSION
        col2 < 10 in dbsp1,
        col2>=10 AND col2 < 100 in dbsp2, 
        col2 > 100 in dbs

优化存储

您可以使用压缩和合并方法来最小化数据使用的磁盘空间,改善 IBM Informix 的 I/O 性能。表 3 给出了使用某些方法来最小化所用磁盘空间的时机。

表 3. 减少数据使用的磁盘空间量的方法
存储优化方法用途使用时机
压缩数据压缩表或碎片行中的数据,减少需要的磁盘空间量。压缩数据后,也可以合并一个表或碎片中剩余的空闲空间,将空闲空间返回到 dbspace。当您希望减少表中的数据大小时
重新打包数据合并表和碎片中的空闲空间压缩数据后,或者在希望合并表或碎片中的空闲空间时独立执行
精减数据将空闲空间返回到 dbspace压缩或重新包装数据后,并且希望将空闲空间返回到 dbspace
对表盘区进行碎片整理将数据行一起放在连续、合并的盘区中当频繁更新的表数据分散在多个不连续的盘区时

理解压缩

压缩是服务器将数据行以压缩格式存储在磁盘上的功能。压缩数据具有以下好处:

  • 显著节省磁盘存储空间
  • 减少压缩分区的磁盘使用
  • 显著节省逻辑日志使用,这节省了更多空间,可在压缩操作完成后预防高吞吐量 OLTP 的瓶颈
  • 更小的缓冲池,因为更多数据可放在同样大小的池中
  • 由于以下原因而减少了 I/O 活动:
    • 可在一个页面上放入比未压缩的行更多的压缩行。
    • 压缩行的插入、更新和删除操作的日志记录更小。
    • 较老且不常访问的时间碎片数据以压缩的形式存在,而较新且经常访问的数据保持未压缩形式。
    • 释放表不再需要空间。
    • 备份和还原执行得更快。

I/O 约束 (I/O-bound) 表(例如具有较低的缓存命中率的表)是压缩的不错候选对象。在 OLTP 环境中,压缩 I/O 约束表可改善性能。

如果应用程序在高缓冲区缓存命中率下运行,并且如果高性能比空间使用更重要,您可能不希望压缩数据,因为压缩可能稍微降低性能。

因为压缩的数据涵盖更少的页面,并且每个页面具有比未压缩数据更多的行,所以查询优化器可能在压缩后选择不同的计划。

如果使用了企业复制 (ER),在一个复制服务器上压缩数据不会影响任何其他复制服务器上的数据。

不能使用 onload 和 onunload 实用程序在数据库之间转移压缩的数据。必须首先解压压缩表和碎片中的数据,才能使用 onload 和 onunload 实用程序。

要执行压缩相关的操作,可运行包含带压缩参数的 SQL 管理 API 命令的 SQL 语句。压缩相关的操作包括 enable compression、estimate_compression、create_dictionary、compress、repack、repack_offline、shrink、uncompress 和 uncompress_offline 操作。

compress、uncompress 和 uncompress_offline 等压缩操作可能使用大量日志文件。如果您希望运行的任何工作负载(包括但不限于这些压缩操作)比每 30 秒使用一个日志文件更快的速度来使用日志文件,那么您需要将日志配置得更大。

不要丢弃 Change Data Capture (CDC) API 正在使用的 dbspace,只要该 dbspace 曾包含压缩表。这可能会删除 CDC 仍然需要的压缩字典。压缩的主要替代方法是购买更多物理存储。减少 I/O 约束的工作负载中的瓶颈的主要替代方法是购买更多物理内存来启用缓冲池的扩展。

了解您可以压缩哪些数据

具有经常重复的长模式的表或表碎片数据非常适合压缩。某些类型的数据(比如文本)可能比其他类型的数据(比如数字数据)更适合压缩,因为文本等数据类型可能包含更长且更常重复的模式。

但是,单单根据数据类型,无法预测压缩率。以下环境也影响着压缩率。

  • 不同语言或字符集的文本可能具有不同的压缩率,即使文本存储在 CHAR 或 VARCHAR 列中。
  • 大部分都是 0 的数字数据可能具有较高的压缩率,而差异更大的数字数据可能具有较低的压缩率。
  • 具有较长空白空间的数据具有很高的压缩率。
  • 已使用其他某种算法压缩的数据或已加密的数据可能具有较低的压缩率。

IBM Informix 可压缩任何数据类型组合,因为它将所有要压缩的数据都视为非结构化的字节序列。因此,服务器可压缩跨越多列的模式,例如城市、街道和邮政编码组合。(IBM Informix 以压缩数据前存在的相同顺序解压字节序列。)

可压缩的数据类型没有限制。

压缩仅适用于数据行的内容,包括跨越多页的行的任何剩余部分,还适用于包含在逻辑日志记录中的行的图像。

行中许多类型的大对象数据(比如图像和声音抽样)可能已压缩,所以再次压缩数据不会获得任何额外的空间节省。

了解您无法压缩哪些数据

您不能压缩索引中的数据,无法压缩某些类型的表和碎片中的数据。

您无法压缩以下地方的行中数据:

  • sysmaster、sysutils、sysuser、syscdr 和 syscdcv1 数据库中的表或碎片
  • 目录
  • 临时表
  • 虚拟表接口表
  • tblspace。这些是隐藏的碎片,每个 dbspace 一个。每个 tblspace 包含 dbspace 中所有碎片的元数据。
  • 内部分区表
  • 字典表,每个 dbspace 一个。这些表包含该 dbspace 中压缩的碎片或表的压缩字典,以及这些字典的元数据。
  • 索引
  • 一个表,如果该表上执行了在线索引构建操作

压缩不适用于索引数据、存储在行外部的 LOB 数据或任何其他形式的非行数据。

加密的数据、已使用另一种算法压缩的数据,以及没有重复性的长模式的数据压缩率都很低,或者不能进行压缩。尝试不要在具有频繁模式的列之间放置具有数据压缩率低的列,以避免对可压缩列跨越模式造成潜在的破坏。

如果 XML 数据的第一部分存储在一行中,剩余部分存储在行外,那么压缩仅适用于存储在行中的部分。

只有在压缩行的图像比未压缩的图像小时,IBM Informix 才会压缩行的图像。即使压缩的行仅比它们未压缩的图像小一点,节省少量的空间也可使服务器在页面上放入更多行。

理解压缩率

压缩率取决于压缩的数据。IBM Informix 使用的压缩算法是一种基于字典的算法,它对在构建字典时抽样的数据中发现的最常见的数据模式(按长度分配权重)执行操作。

如果典型的数据分布不同于在创建字典时抽样的数据,压缩率可能降低。

可能实现的最高压缩率为 90%。这是因为,任何字节序列的最高压缩率都是通过将每组 15 个字节替换为一个 12 位的符号编号来实现的,这会得到一个只有原始图像大小 10% 的压缩图像。但是,90% 的压缩率很少实现,因为 IBM Informix 会向每个压缩图像添加了一字节的元数据。

估算压缩率

在压缩一个表或表碎片之前,IBM Informix 可估算压缩数据后可节省的空间量。显示的比率是基于行数据抽样的估算值。所节省空间的实际比率可能非常小。

IBM Informix 通过随机抽样行数据(使用与构建字典时相同的抽样算法)并汇总以下项目的大小来估算压缩率:

  • 未压缩的行图像
  • 使用一个新压缩字典压缩的行图像,该字典是由估算压缩率命令临时创建的
  • 使用现有字典(如果存在)压缩的行图像。如果没有现有的字典,此值将与未压缩的行图像大小总和相同。

由于一个细微的抽样错误或估算是基于行的原始可压缩性,实际实现的空间节省率可能不同。例如,服务器一般会尝试将整行放在一个页面上。所以,如果每个未压缩的行几乎填满了整个页面,并且压缩率小于 50%,那么压缩的行仍将填满每个页面的一半以上空间;即使在压缩后,服务器也可能将每行放在一个独立的页面上。在此情况下,尽管估算的压缩率可能类似于 45%,但实际的空间节省可能为 0%。

未压缩的行占用了每个页面空间的一半多一点。因此,每个未压缩的行实际将占用一个完整的页面,因为一个页面无法放入两行。例如,估算的压缩率可能类似于 5%,但这可能仅够将行压缩到小于每个页面的一半。因此,在压缩后,一个页面上将能放入两行,实际的空间节省可能为 50%。

因为 IBM Informix 从不会在单页上存储超过 255 行,所以实际实现的压缩率也可能与估算值不同。因此,小行或大页面可减少压缩可实现的总节省空间。例如,如果在压缩前一页中可放入 200 行,无论在压缩时这些行有多小,最有效的压缩率可能是大约 20%,因为在压缩后一个页面上只能放入 255 行。

如果使用比最小页面尺寸更大的页面,一种增加空间节省的方式是换用更小的页面,已实现以下事实:

  • 不会在达到 255 行的限制。
  • 如果仍然达到此限制,页面上未使用的空间更少。

如果压缩操作与重新包装操作、精减操作或重新包装和精减操作相结合,可能会节省比估算值更多(或更少)的空间。只有在一个页面上放入比未压缩的行更多的压缩行时,重新包装操作才可能节省更多空间。如果重新包装操作释放了空间,精减操作可以在 dbspace 级别节省空间。

探讨压缩字典

每个压缩的碎片和每个压缩的未碎片化表均有一个独立的压缩字典。每个压缩字典都是碎片或表数据中经常发生的模式和取代这些模式的符号编号的库。

压缩字典使用从一个包含至少 2,000 行的碎片或未碎片化表中随机抽样的数据而构建。如果碎片或表没有包含 2,000 行,IBM Informix 不会构建压缩字典。

压缩字典可存储最多 3,840 个模式,每个模式的长度为 2 到 15 字节。(比 7 字节更长的模式会减少字典可包含的模式总数。)每个模式使用压缩行中的一个 12 位符号编号来表示。要压缩,输入行图像中的字节序列必须与字典中一个完整的模式准确匹配。没有足够的模式与字典匹配的行则无法进行压缩,因为不完全匹配的输入行的每个字节会在压缩图像中被替换为 12 比特(1.5 个字节)。

IBM Informix 尝试捕获最佳的压缩模式(模式的频率乘以长度)。数据的压缩方式是,将出现的模式替换为字典中相应的符号编号,将不与任何模式匹配的字节位置替换为特殊的保留符号编号。

一个 dbspace 中的表或碎片的所有字典存储在该 dbspace 中一个隐藏字典表中。sysmaster 数据库中的 syscompdicts_full 表和 syscompdicts 视图提供了压缩字典的信息。

通常,存储一个压缩碎片或表的压缩字典需要大约 100 KB 的空间。因此,非常小的表不是好的压缩候选者,因为您可能无法通过压缩行获得足够的空间来补偿压缩字典的成本。

此外,IBM Informix 无法压缩小于 4 字节的一个单独行。这是因为服务器必须留出空间,以防行图像在以后增长到超出了页面大小。因此,如果碎片或未碎片化表包含 4 字节或短于 4 字节的行,您不应尝试压缩它们。

使用 API 接口管理压缩

所有压缩操作都使用一个 SQL 管理 API admin() 或 task() 任务来执行。压缩操作会创建一个压缩字典(如果不存在),并且它会在不移动行的情况压缩行。

以下是使用 API 命令的前提条件:

  • 一个表上或该表的每个碎片中拥有至少 2,000 行,而不只是表中总共有 2,000 行。
  • 您必须能够连接 sysadmin 数据库(默认情况下,只有用户 informix 能连接),并且您必须是数据库系统管理员。
  • 如果您期望运行的任何工作负载(包括但不限于压缩操作)将比每 30 秒使用一个日志文件更快的速度使用日志文件,您必须将日志配置为比它们当前更大的空间。

对于表,表名称是强制选项。数据库和所有者名称则是可选的。如果不指定数据库或所有者名称,IBM Informix 会使用当前数据库和所有者名称。

对于碎片,partnum_list 是属于同一个表的分区编号的一个空格分隔列表。

估算压缩率

此操作显示预计可实现的压缩率、当前的压缩率、获得或损失的百分比估算值、每个碎片的分区编号,以及表的全名(包括数据库、所有者和表名称)。如果表未压缩,当前的压缩率为 0%。

对表和碎片的压缩估算输出大体类似,但表的输出始终会显示表中的所有碎片,而碎片的输出仅显示指定碎片的信息。清单 72 显示了一个表的压缩率估算输出。

清单 72. 估算一个表
EXECUTE FUNCTION task("table estimate_compression",
     "table_name", "database_name", "owner_name");

清单 73 显示了一个碎片的压缩率估算输出。

清单 73. 估算一个碎片
EXECUTE FUNCTION task("fragment estimate_compression",
     "partnum_list");

例如,清单 74 中的命令告诉 IBM Informix 估算压缩 store123 数据库中一个名为 cash_transaction 的表的收益,该数据库的所有者是 wong。

清单 74. 碎片压缩的结果
EXECUTE FUNCTION task ("table estimate_compression",
     "cash_transaction", "store123", "wong");

在 表 4 中的示例中,第一行的结果是针对已压缩的一个碎片的。第二个碎片为未压缩。如果重新压缩第一个碎片,节省的空间会增加 0.4%。如果压缩第二个碎片,节省的空间会增加 75.7%。

表 4. 估算压缩率
估算的压缩率当前压缩率变化部分编号
75.7%75.3%+0.40x00200003store123:wong.cash_transaction
75.7%0.0%+75.70x00300002store123:wong.cash_transaction

创建压缩字典

可以基于现有的行创建一个压缩字典,供 IBM Informix 在压缩一个表或表碎片中的数据时使用。创建字典后,IBM Informix 将使用字典来压缩新插入或更新的行。

如果压缩字典不存在,您也可以在运行压缩命令时创建一个。两个命令之间的惟一区别是,压缩命令也会压缩表或碎片中的现有数据。

如果希望为一个碎片创建压缩字典,该碎片必须包含至少 2,000 行。如果希望为一个表创建压缩字典,该表的每个碎片都必须包含至少 2,000 行。

清单 75 显示了表的压缩字典 API 命令的输出。

清单 75. 表的压缩字典 API 命令
EXECUTE FUNCTION task("table create_dictionary",
    "table_name","database_name", "owner_name");

清单 76 显示了一个碎片的压缩字典 API 命令的输出。

清单 76. 一个碎片的压缩字典 API 命令
EXECUTE FUNCTION task("fragment create_dictionary", 
     "partnum_list");

清单 77 给出了一个创建压缩字典表的示例命令。

清单 77. 创建压缩字典
EXECUTE FUNCTION task("table create_dictionary","classical","music","Joe");

要在创建压缩字典后压缩现有表或碎片行中的数据,必须运行一个压缩命令。

只有在解压表或碎片后,才能删除压缩字典。

压缩表和表碎片

压缩操作会创建一个压缩字典(如果不存在),它在压缩行时不会移动它们。但是,分配给该表的空间将在压缩行之后保持不变。

清单 78 给出了压缩一个表的语句。

清单 78. 压缩一个表
EXECUTE FUNCTION task("table compress", "table_name",
     "database_name", "owner_name");

清单 79 给出了一个示例。

清单 79. 压缩一个表的示例
EXECUTE FUNCTION task("table compress","opera","music","bob");

清单 80 给出了压缩一个碎片的语句。

清单 80. 压缩一个碎片
EXECUTE FUNCTION task("fragment compress",
     "partnum_list");

清单 81 给出了一个示例。

清单 81. 压缩一个碎片的示例
EXECUTE FUNCTION admin("fragment compress","14680071");

如果中断一个压缩操作并重新发出压缩命令,IBM Informix 会继续使用现有的压缩字典进行压缩。

如果在执行一个压缩操作后更改表的碎片战略,必须重新压缩。

合并表中的空闲空间

如果希望合并空闲空间或返回空闲空间,而不执行压缩或重新压缩,您可以运行一个命令来告诉服务器重新包装、精减或重新包装并精减。也可以扩展这些参数以包含重新包装和精减的以下任何组合:

  • 压缩重新包装
  • 压缩重新包装精减
  • 压缩精减

您可以在压缩表或碎片时,或者不压缩而独立地合并(重新包装)表和碎片中的空闲空间。此操作将表末尾的空闲空间释放给 dbspace,供其他表使用。

您可以使用 repack 或 repack_offline 参数在线或离线执行重新包装操作。repack_offline 操作与 repack 操作相同,但 IBM Informix 在执行该操作时会在表或碎片上持有一个独占锁。此操作会在操作完成之前阻止对数据的所有其他访问。

如果在执行 repack 操作时在表或碎片中发生了轻量附加,repack 操作将不会完成表或碎片末尾的空间的合并。repack 操作不会完成是因为在已发生 repack 操作的地方添加了新的盘区,所以空间无法返回到 dbspace。

要完成重新包装过程,必须在完成定量附加活动后执行第二个 repack 操作。第二个 repack 操作以第一个 repack 操作的工作为基础。

在完成 repack_offline 操作之前丢弃或禁用索引可减少服务器完成该操作的时间量。之后,您可以重新创建或重新启用索引,最好利用 PDQ 来完成。丢弃或禁用索引,然后再次创建或启用它们,这可能比完成一个 repack_offline 操作更快。

清单 82 给出了在线或离线合并一个表的空闲空间的语句。

清单 82. 合并一个表的空闲空间
EXECUTE FUNCTION task("table repack", "table_name",
     "database_name", "owner_name");
EXECUTE FUNCTION task("table repack_offline",
     "table_name","database_name", "owner_name");

清单 83 给出了在线或离线合并一个碎片的空闲空间的语句。

清单 83. 合并一个碎片的空闲空间
EXECUTE FUNCTION task("fragment repack", "partnum_list");
EXECUTE FUNCTION task("fragment repack_offline",
     "partnum_list");

可选择地扩展这些参数以在下列任何组合中包含压缩和精减:

  • 压缩重新包装
  • 下列任何组合精减
  • 重新包装精减

清单 84 给出了一些示例。

清单 84. 合并空闲空间的示例
EXECUTE FUNCTION task("table repack","opera","music","bob");
EXECUTE FUNCTION task("table repack_offline","folk","music","janna");
EXECUTE FUNCTION task("fragment repack shrink", "14680071");

您可以取消带 compress 参数的命令,例如通过在 DB-Access 中键入 CTRL+C。您可以在前一个中断的命令之后重新发出带 repack 或 repack_offline 参数的命令。compress 和 repack 操作会记入日志,但它们以小部分的形式运行。

将空闲空间返回到 dbspace

在压缩、重新包装或压缩并重新包装表或碎片时,可以将空闲空间返回到 dbspace(精减空间)。或者可以独立地返回空闲空间,而不压缩或重新包装。返回空闲空间会减少碎片或表的总大小。

您可以安全地精减整个表,而不会破坏表的分配战略。例如,如果有一个碎片表,其中包含一星期中每一天的一个碎片和许多供未来使用的预先分配的碎片,您可以精减该表,而不会破坏此分配战略。如果表是空的,IBM Informix 会将该表精减到在创建表时指定的初始盘区大小。

当发起一个 shrink 操作时,IBM Informix 会按以下方式缩短盘区:

  • 它将除第一个盘区外的所有盘区缩短到尽可能小。
  • 如果一个表完全在第一个盘区(例如,因为该表是一个空表),IBM Informix 不会将第一个盘区精减到比在使用 CREATE TABLE 语句创建表时指定的盘区大小更小。

您可以使用 ALTER TABLE 语句的 MODIFY EXTENT SIZE 子句来减少当前的盘区大小。这么做后,您可以重新运行 shrink 操作来将第一个盘区精减到新盘区的大小。

清单 85 给出了将表的空闲空间返回到 dbspace 的语句。

清单 85. 将表的空闲空间返回到 dbspace
EXECUTE FUNCTION admin("table shrink",
    "table_name","database_name", "owner_name");

清单 86 给出了将碎片的空闲空间返回到 dbspace 的语句。

清单 86. 将碎片的空闲空间返回到 dbspace
EXECUTE FUNCTION task("fragment shrink", "partnum_list");

您也可选择性地扩展参数以在下列组合中包含压缩和重新包装:

  • 压缩重新包装精减
  • 压缩精减
  • 重新包装精减

清单 87 给出了一些示例。

清单 87. 将空闲空间返回到 dbspace 的示例
EXECUTE FUNCTION task("table shrink","opera","music","bob"); 
EXECUTE FUNCTION task("fragment repack shrink," "14680071");

解压数据

您可以解压以前压缩的表和碎片。解压表或碎片会停用新 insert 和 update 操作的压缩,解压所有压缩的行,停用压缩字典,并为无法再放在原始页面中的行分配新页面。

您可以使用 uncompress 或 uncompress_offline 参数在线或离线解压。uncompress_offline 操作与 uncompress 操作类似,但执行此操作时会在碎片上持有一个独占锁,以在操作完成之前阻止对碎片数据的所有其他访问。

在完成 uncompress_offline 操作之前丢弃或禁用索引可减少服务器完成该操作所花的时间量。之后,您可以重新创建或重新启用索引,最好利用 PDQ 来完成。丢弃或禁用索引,然后再次创建或启用它们,这可能比完成一个 repack_offline 或 uncompress_offline 操作更快。

表或碎片必须是压缩的。

清单 88 给出了在线或离线解压一个表的语句。

清单 88. 在线或离线解压一个表
EXECUTE FUNCTION task("table uncompress",
     "table_name","database_name","owner_name");
EXECUTE FUNCTION admin("table
     uncompress_offline","table_name","database_name",
     "owner_name");

清单 89 给出了在线或离线解压一个碎片的语句。

清单 89. 在线或离线解压一个碎片
EXECUTE FUNCTION task("fragment uncompress",
     "partnum_list");
EXECUTE FUNCTION task("fragment uncompress_offline",
     "partnum_list");

清单 90 给出了一些示例。

清单 90. 解压示例
EXECUTE FUNCTION task("table uncompress","rock","music","mario");
EXECUTE FUNCTION task("fragment uncompress_offline","14680071");

如果一个表已解压,IBM Informix 会将该表的字典标记为不活动。IBM Informix 不会删除字典,因为企业复制功能会对早期的日志使用字典。您可以删除不再需要的字典。

您可以取消带 uncompress 参数的命令,例如,通过在 DB-Access 中键入 CTRL+C。

您可以在前一个中断的命令之后重新发出带 uncompress 和 uncompress_offline 参数的命令。compress、repack 和 uncompress 操作会记入日志,但它们以小部分的形式运行。

删除压缩字典

您可以删除特定表或碎片的不活动的压缩字典,可以删除所有不活动的压缩字典,或者您可以删除截至指定日期的所有不活动的压缩字典。在删除为表和碎片创建的任何压缩字典之前,必须解压这些表和碎片,这会使字典变得不活动。

不要删除企业复制功能需要的压缩字典。

删除压缩字典的前提条件

  • 在删除关联的字典之前,解压或丢弃表或碎片。只能删除压缩的表或碎片不再使用的压缩字典。
  • 确保企业复制功能没有为早期的日志使用该压缩字典。
  • 使用压缩字典归档任何包含表或碎片的 dbspace,即使您解压了表或碎片中的数据,并且该字典不再活动。

用于删除压缩字典的 API

表 5 提供了 API 命令来删除压缩字典。

表 5. 用于删除压缩字典的 API 命令
Admin() 或 task() 函数参数功能
table purge_dictionary fragment purge_dictionary删除一个特定的、不活动的字典
compression purge_dictionary删除所有字典
compression purge_dictionary删除在特定日期及之前创建的所有字典。请注意,可以使用具有可转换为基于您的地区和环境的 DATE 数据类型的任何日期。例如,可指定 01/31/200901/31/09Jan 31, 2009

清单 91 给出了一个示例。

清单 91. 清除压缩字典的示例
EXECUTE FUNCTION task("compression purge_dictionary","03/08/09");

移动压缩的数据

您可以使用高性能加载器 (HPL) 或任何其他 IBM Informix 实用程序(onunload 和 onload 实用程序除外)来在数据库之前移动压缩的数据。在使用 onunload 和 onload 实用程序之前,必须解压压缩表和碎片中的数据。

dbexport 实用程序会在导出期间自动解压压缩的数据。因此,如果数据库包含具有压缩数据的表或碎片,必须在使用 dbimport 实用程序导出数据之后重新执行压缩。

监视压缩信息

您可以使用 IBM Informix 实用程序、一个 sysmaster 数据库表和一个 sysmaster 视图来显示压缩统计信息、压缩字典信息和压缩字典。表 6 给出了提供压缩信息的实用程序、表和视图。

表 6. 显示压缩信息的实用程序、sysmaster 表和视图
实用程序、表或视图描述
oncheck -pT 选项显示一个表或表碎片中任何已压缩行的编号,以及压缩的表或表碎片行的百分比。如果表或碎片行没有压缩,则输出中不包含 Compressed Data Summary 部分。
onlog -c 选项使用压缩字典展开压缩的数据,显示压缩的日志记录中未压缩的内容。
onstat -g dsk 选项显示表明当前运行的压缩操作进度的信息。
onstat -g ppd 选项显示存在的针对当前打开的已压缩碎片(也称为分区)的活动压缩字典的信息。此选项显示的信息与 sysmaster 数据库中的 syscompdicts 视图相同。
sysmaster 数据库中的 syscompdicts_full 表显示压缩字典和压缩字典二进制对象的元数据。只有用户 informix 可访问此表。
sysmaster 数据库中的 syscompdicts 视图显示与 syscompdicts_full 表相同的信息,但出于安全原因,它不包含 dict_dictionary 列,该列包含压缩字典二进制对象。

您可以使用一个 UNLOAD 语句来将压缩字典从 syscompdicts_full 表卸载到压缩字典文件,如 清单 92 中所示。

清单 92. 卸载压缩字典
UNLOAD TO 'compression_dictionary_file' SELECT * FROM
     sysmaster:syscompdicts_full;

分区碎片整理

您可以通过对分区执行碎片整理来合并不连续的盘区,进而改善性能。

经常更新表可能逐渐变得碎片化,这会降低服务器每次访问该表时的性能。对表执行碎片整理会将数据行放在一起,避免分区标题页溢出问题。对索引执行碎片整理会将所有条目放在一起,改善访问表信息的速度。

defragment 操作将表和索引重组到更少且更大的连续盘区中。关于 defragment 操作的一个常见误解是它会增加日志的使用。

要确定一个表、索引或分区有多少个盘区,可以运行 oncheck -pt 和 oncheck -pT 命令。

要对表、索引或分区执行碎片整理,可运行带 defragment 参数或 defragment partnum 参数的 SQL 管理 API task() 或 admin() 函数,指定您希望执行碎片整理的表名称、索引或分区编号。

限制和考虑事项

在对分区执行碎片整理之前,请检查以下重要的考虑事项:

  • 不能在提交碎片整理请求后停止该请求。
  • 不能对以下对象执行碎片整理:
    • 伪表,比如虚拟表接口 (VTI) 表
    • 具有虚拟索引接口 (VII) 索引的表
    • 包含 B 型树功能索引的表
    • 临时表
    • 外部表
    • 排序文件
    • 视觉 BLOB 文件
    • 系统目录表
  • 不要在您希望执行碎片整理的表或分区上发出相冲突的操作。第一个操作必须完成之后才能启动第二个操作。如果第一个操作仍在运行,对第二个操作的请求将返回一个错误。下面的列表包含冲突操作的示例:
    • 一次只能在一个分区上处理一个碎片整理请求。
    • 一次只能在一个 dbspace 上处理一个碎片整理请求。
    • 在表或分区上运行 DDL 语句时,比如 DROP TABLE 或 ALTER FRAGMENT,不能对该表执行碎片整理。
    • 表正在截断时不能执行碎片整理。
    • 表正在压缩或解压时不能执行碎片整理。
    • 正在构建在线索引时不能对表执行碎片整理。
    • 表上设置了独占访问时不能执行碎片整理。

如果在完成碎片整理请求时出现问题,错误消息会发送到在线日志文件。

用于对表执行碎片整理的 API 接口

您可以将 defragment 参数和 admin() 或 task() 函数来对表或索引执行碎片整理,以合并不连续的盘区。您可以使用 清单 93 中的语法指定 defragment 参数或 defragment partnum 参数。

清单 93. 对一个表执行碎片整理
EXECUTE FUNCTION task("defragment","database:owner:table")
EXECUTE FUNCTION task("defragment partnum", "partnum_list")

表 7 给出了对表执行碎片整理时的元素和考虑事项。

表 7. 元素信息
元素描述重要考虑事项
Database包含您希望执行碎片整理的表或索引的数据库名称
Owner表所有者的用户 ID
Table要执行碎片整理的表名称
Partnum_list要执行碎片整理的一个或多个分区编号使用一个逗号分隔的分区编号列表来指定多个分区。

使用 defragment 参数对特定表执行碎片整理。使用 defragment partnum 参数对一个或多个特定的磁盘分区执行碎片整理。

有关碎片整理的信息存储在共享内存中。可使用 oncheck -pt 和 oncheck -pT 命令来显示特定表或碎片的盘区数量信息。可使用 onstat -g defragment 来显示活动的碎片整理请求的信息。

如果碎片整理请求减少了至少 1 个盘区,该请求会返回 0(成功),即使分区中存在许多盘区。

如果一个分区只有一个盘区,碎片整理请求返回 0,以表示请求成功,即使没有合并任何盘区。

清单 94 给出了对 stores_demo 数据库中的 customer 表执行碎片整理的示例。

清单 94. 对 stores_demo 数据库中的 customer 表执行碎片整理
EXECUTE FUNCTION task("defragment","stores_demo:informix.customer");

清单 95 给出了指定要对其索引执行碎片整理的分区编号的示例。

清单 95. 指定要对其索引执行碎片整理的分区编号
EXECUTE FUNCTION task("defragment partnum","2097154");

清单 96 给出了对一组分区执行碎片整理的示例。

清单 96. 对一组分区执行碎片整理
EXECUTE FUNCTION task("defragment partnum", "16777217,28477346");

参考资料

学习

获得产品和技术

讨论

条评论

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=829839
ArticleTitle=Informix 11.70 系统管理认证考试 919 准备教程,第 2 部分: Informix 空间管理
publish-date=08092012