目前大多企业 DB2 生产环境都要求高可用,不能承担片刻停机带来的损失。当 DBA 希望将表从一个表空间移动到另一个表空间中,在 DB2 V9.7 以前的版本中要实现这个目标比较复杂,总有一段时间表对外是不可用的。DB2 V9.7 提供了 ADMIN_MOVE_TABLE 存储过程将表中的数据移至名称相同的新表对象,而新表是存放在不同的表空间上具有不同的存储特征,同时数据保持联机可供访问。我们还可以在表移动时为表生成新的优化压缩字典。
DB2 V9.7 通过自动将表数据移至新表对象并同时允许数据保持联机以进行查询、插入、更新和删除访问,降低了企业的总体拥有成本(TCO)和复杂性。
在表数据移动过程中我们还可以使用 ADMIN_MOVE_TABLE 存储过程修改表的定义,如增加删除列、修改列数据类型等。
ADMIN_MOVE_TABLE 过程涉及三个表:
数据移动过程还涉及一个表被成为协议表(protocol table),这个表将用于保存数据移动的过程数据和配置信息,如数据移动使用的参数、COPY 开始的时间、结束时间、COPY 使用的选项等。此表定义如下:
C:\>db2 describe table systools.ADMIN_MOVE_TABLE 数据类型 列 列名 模式 数据类型名称 长 小数位 NULL --------------- --------- ------------------- ---------- ----- - ----- TABSCHEMA SYSIBM VARCHAR 128 0 否 TABNAME SYSIBM VARCHAR 128 0 否 KEY SYSIBM VARCHAR 32 0 否 VALUE SYSIBM CLOB 10485760 0 是 |
其中关键字(KEY)都有特定含义,当我们对表数据移动进行问题诊断、调整性能时都会使用到该表。
ADMIN_MOVE_TABLE 过程将首先创建源表的影子副本。在复制阶段,DB2 将使用触发器捕获对源表的插入、更新和删除操作并将其放入到登台表中。完成复制阶段后,DB2 在登台表中捕获的数据更改操作将在影子副本中重现。最后 DB2 使用 ADMIN_MOVE_TABLE 过程将使表短暂脱机以交换对象名。ADMIN_MOVE_TABLE 默认情况下使用 INSERT Cursor 的方式将数据从源表复制到目标表,也可以指定选项使用 LOAD 方式复制数据以提高性能。
从过程上看,表数据移动大致分为以下几个阶段:
我们需要注意的是 ADMIN_MOVE_TABLE 可以将源表上定义的触发器、视图也同时移动到目标表,但是当前它并不能支持将外键关系复制到目标表,无论源表是外键的父表还是子表。因此如果源表上有外键关系存在,我们首先需要捕获这些外键定义,然后在移动完成后在目标表上重新创建。
DB2 中存在两种合法的 ADMIN_MOVE_TABLE 语法形式。第一种方法用于我们修改在目标表上修改指定的部分的定义,如我们有一个定义很长的表,而我们希望做的仅仅时修改表存放的表空间,用第一种语法我们就不需要重新创建表而直接使用 ADMIN_MOVE_TABLE 修改。我们需要做的仅仅是在参数中指定 data_tbsp、index_tbsp、和 lob_tbsp,而把其他可选参数设置为空即可。
DB2 提供的第二种语法让我们更加灵活、方便的控制目标表的创建,而不使用存储过程创建目标表。这让我们能够在第一种方法没有办法创建目标表的情况下手工创建目标表。
>>-ADMIN_MOVE_TABLE--(--tabschema--,--tabname--,---------------->
>--data_tbsp--,--index_tbsp--,--lob_tbsp--,--mdc_cols--,-------->
.-,-------.
V |
>--partkey_cols--,--data_part--,--coldef--,----options-+--,----->
>--operation--)------------------------------------------------><
|
>>-ADMIN_MOVE_TABLE--(--tabschema--,--tabname--,---------------->
.-,-------.
V |
>--target_tabname--,----options-+--,--operation--)-------------><
|
存储过程中使用的参数含义如下:
当指定目标表的名字时,存在以下约束:
我们知道 DB2 在移动表数据时,会使用表 systools .ADMIN_MOVE_TABLE 保存数据移动配置和状态信息,该表是以 tabschema、tabname、key 列为主键。ADMIN_MOVE_TABLE_UTIL 存储过程可以用来更改协议表 ADMIN_MOVE_TABLE 中定义的键值。
清单 4. ADMIN_MOVE_TABLE_UTIL 语法
>>-ADMIN_MOVE_TABLE_UTIL--(--tabschema--,--tabname--,--action--,--key--,--value--)->< |
其中:
清单 5. ADMIN_MOVE_TABLE_UTIL 例子
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','INIT')
CALL SYSPROC.ADMIN_MOVE_TABLE_UTIL('SVALENTI','T1','UPSERT',
'DEEPCOMPRESSION_SAMPLE','30720')
CALL SYSPROC.ADMIN_MOVE_TABLE_UTIL('SVALENTI','T1','DELETE','COPY_INDEXSCHEMA','')
CALL SYSPROC.ADMIN_MOVE_TABLE_UTIL('SVALENTI','T1','DELETE','COPY_INDEXNAME','')
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','COPY')
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','REPLAY')
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','SWAP')
|
上面清单中首先使用默认值启动数据移动 INIT 阶段,然后使用 ADMIN_MOVE_TABLE_UTIL 过程修改压缩采样大小为 30720 KB,并删除 COPY_INDEXSCHEMA、COPY_INDEXNAME 设置,然后继续数据移动过程。
使用 DB2 在线表移动功能,我们可以进行:
我们首先创建测试表 EMP_TEST,并创建索引,然后向表中插入 10 万条测试数据。
CREATE TABLE emp_test ( EMPNO INTEGER NOT NULL, first_name VARCHAR(128) NOT NULL, last_name VARCHAR(128), SALARY DECIMAL, BONUS DECIMAL, COMM DECIMAL, CONSTRAINT EMPNO_pk PRIMARY KEY (EMPNO) ) IN USERSPACE1; Create index first_name_idx on emp_test(first_name); Create index last_name_idx on emp_test(last_name); INSERT INTO emp_test (EMPNO, first_name, last_name,SALARY,BONUS,COMM) WITH TEMP (COUNTER, first_name, last_name,SALARY,BONUS,COMM) AS ( VALUES (0, VARCHAR(MOD(INT(RAND() * 100000), 99999)), VARCHAR(MOD(INT(RAND() * 100000), 99999)), MOD(INT(RAND() * 100000), 99999), MOD(INT(RAND() * 100000), 99999), MOD(INT(RAND() * 100000), 99999) ) UNION ALL SELECT (COUNTER + 1), VARCHAR(MOD(INT(RAND() * 100000), 99999)), VARCHAR(MOD(INT(RAND() * 100000), 99999)), MOD(INT(RAND() * 100000), 99999), MOD(INT(RAND() * 100000), 99999), MOD(INT(RAND() * 100000), 99999) FROM TEMP WHERE (COUNTER + 1) < 100000 ) SELECT COUNTER, first_name, last_name,SALARY,BONUS,COMM FROM TEMP ; runstats on table db2admin.emp_test and indexes all; |
我们创建测试表空间 TS_TEST,然后将 EMP_TEST 中的数据、索引、LONG 对象全部移动到 TS_TEST 表空间中。
CREATE TABLESPACE TS_TEST;
CALL SYSPROC.ADMIN_MOVE_TABLE
('DB2ADMIN', 'EMP_TEST',
'TS_TEST', 'TS_TEST', 'TS_TEST',
'', '', '', '', '', 'MOVE');
结果集 1
--------------
KEY VALUE
-------------------------- ------------------------
AUTHID USERID
CLEANUP_END 2009-08-18-14.38.40.390000
CLEANUP_START 2009-08-18-14.38.39.827000
COPY_END 2009-08-18-14.38.29.546000
COPY_OPTS OVER_INDEX,ARRAY_INSERT
COPY_START 2009-08-18-14.38.20.452000
COPY_TOTAL_ROWS 100000
INDEXNAME EMPNO_PK
INDEXSCHEMA USERID
INDEX_CREATION_TOTAL_TIME 7
INIT_END 2009-08-18-14.38.20.311000
INIT_START 2009-08-18-14.38.19.124000
REPLAY_END 2009-08-18-14.38.38.905000
REPLAY_START 2009-08-18-14.38.29.561000
REPLAY_TOTAL_ROWS 0
REPLAY_TOTAL_TIME 0
STATUS COMPLETE
SWAP_END 2009-08-18-14.38.39.733000
SWAP_RETRIES 0
SWAP_START 2009-08-18-14.38.39.108000
VERSION 09.07.0000
21 条记录已选择。
返回状态 = 0
|
数据移动结果集实际上是从协议表 ADMIN_MOVE_TABLE 中选择出来的数据。结果集显示 COPY 10 万行数据花费了 9.1 秒,REPLAY 花费 9.4 秒,SWAP 花费 0.6 秒,合计 21.1 秒,这表明数据移动过程绝大部分时间花费在 COPY 和 REPLAY 阶段。如果我们希望能够优化数据移动过程,应主要从这个阶段入手。
在 COPY 有两个对性能影响比较大的选项,一个为 COPY_WITH_INDEXES,一个为 COPY_USE_LOAD。
COPY_WITH_INDEXES 选择指定在 COPY 源表之前就创建索引,这样在复制过程中需要对索引进行维护,因此性能会下降,不过优点是索引创建收到事务保护。默认情况下不使用 COPY_WITH_INDEXES,如果大家在协议表 ADMIN_MOVE_TABLE 的 COPY 选项中发现”WITH_INDEXES”则表示先创建了索引。
DB2 进行表数据移动时,默认采用 INSERT FROM CURSOR 方法进行 COPY,这种方法需要对复制的每一行执行一个 Insert 操作,引起的负担与我们平时执行 Insert 完全相同。我们可以通过设置选项 COPY_USE_LOAD 采用 LOAD API 方式进行 COPY 以提高性能。使用 LOAD API 的优点是:
不过需要注意的是,使用 LOAD API 时,与使用 LOAD 命令加载数据一样,过程是不可恢复的。因此最好在 LOAD 后执行一次数据库备份,或者在 LOAD 时指定选项 COPY 或 KEEP 以保存一份原始数据。
CALL SYSPROC.ADMIN_MOVE_TABLE
('USERID', 'EMP_TEST', 'NEW_TS', 'NEW_TS', 'NEW_TS', '', '', '', '', 'COPY_USE_LOAD,FORCE', 'MOVE')
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
结果集 1
--------------
KEY VALUE
---------------------- ----------------------
AUTHID USERID
CLEANUP_END 2009-08-18-14.44.48.952000
CLEANUP_START 2009-08-18-14.44.48.327000
COPY_END 2009-08-18-14.44.45.155000
COPY_OPTS OVER_INDEX,LOAD,WITH_INDEXES
COPY_START 2009-08-18-14.44.37.171000
COPY_TOTAL_ROWS 100000
INDEXNAME EMPNO_PK
INDEXSCHEMA USERID
INDEX_CREATION_TOTAL_TIME 1
INIT_END 2009-08-18-14.44.36.640000
INIT_START 2009-08-18-14.44.35.436000
REPLAY_END 2009-08-18-14.44.47.186000
REPLAY_START 2009-08-18-14.44.45.155000
REPLAY_TOTAL_ROWS 0
REPLAY_TOTAL_TIME 0
STATUS COMPLETE
SWAP_END 2009-08-18-14.44.48.155000
SWAP_RETRIES 0
SWAP_START 2009-08-18-14.44.47.186000
VERSION 09.07.0000
21 条记录已选择。
返回状态 = 0
|
上述结果集显示 COPY 10 万行数据花费了 8 秒,REPLAY 花费 2 秒,SWAP 花费 1 秒,合计 13.1 秒。在这个例子中我们使用了 COPY_USE_LOAD 选项,即采用 LOAD API 加载数据,比使用 INSERT FROM CURSOR 方法快 36%。
DB2 V9.7 提供的 ADMIN_MOVE_TABLE 存储过程能够帮助 DBA 在线的修改表,包括表空间、表定列义、表压缩、表分区等,这为 DBA 保持系统高可用性。在使用 ADMIN_MOVE_TABLE 存储过程时,我们也会经常碰到错误,主要和表移动状态有关:
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/15082138/viewspace-619593/ ,如需转载,请注明出处,否则将追究法律责任。