准备要处理的表
您必须执行以下任务来准备要在 Oracle GoldenGate 环境中用于 Db2 LUW 的表。
禁用触发器和级联约束条件
对目标 Db2 LUW 表禁用触发器、级联删除约束条件和级联更新约束条件。Oracle GoldenGate 将复制由触发器或级联约束条件产生的 DML。如果在目标表上激活了相同的触发器或约束条件,则由于复制的版本,该触发器或约束条件将变得冗余,并且数据库将返回错误。请考虑以下示例,其中源表为 emp_src 和 salary_src,目标表为 emp_targ 和 salary_targ。
-
对
emp_src发出删除。 -
它将删除级联到
salary_src。 -
Oracle GoldenGate 会将两项删除操作发送到目标。
-
父删除首先到达,并应用于
emp_targ。 -
父删除将删除级联到
salary_targ。 -
salary_src中的级联删除将应用于salary_targ。 -
无法找到该行,因为已在步骤 5 中将其删除。
确保表的行唯一性
Oracle GoldenGate 在源表和目标表上需要某种形式的唯一行标识符,以查找用于复制更新和删除的正确目标行。
除非 TABLE 或 MAP 语句中使用 KEYCOLS 子句,否则 Oracle GoldenGate 将按以下优先级顺序选择要使用的行标识符:
-
主键
-
按字母数字顺序排列的第一个不包含时间戳或非实体化计算列的唯一键。
-
如果上述关键字类型均不存在(即使表中可能定义了其他类型的关键字),则 Oracle GoldenGate 将构造所有列的伪关键字数据库允许在唯一密钥中使用,但不包括 Oracle GoldenGate 在密钥中不支持的密钥或从 Oracle GoldenGate 配置中排除的密钥。
注:如果表中存在其他不可使用的关键字,或者表中根本没有关键字,则 Oracle GoldenGate 会将相应的消息记录到报表文件中。从所有列构建密钥会妨碍 Oracle GoldenGate 在源系统上的性能。在目标上,此键会导致复制使用较大且效率较低的
WHERE子句。 -
如果表没有相应的键,或者您希望未使用现有键,则可以定义替代键(如果表具有始终包含唯一值的列)。您可以通过在 Extract
TABLE参数和 ReplicatMAP参数中包含KEYCOLS子句来定义此替代关键字。指定的键将覆盖 Oracle GoldenGate 找到的任何现有主键或唯一键。请参阅TABLE \| MAP中的 Parameters and Functions Reference for Oracle GoldenGate 。
使用 KEYCOLS 指定定制密钥
如果表没有上述行标识符类型之一,或者您希望不使用这些标识符,则可以定义替代键(如果表具有始终包含唯一值的列)。您可以通过在 Extract TABLE 参数和 Replicat MAP 参数中包含 KEYCOLS 子句来定义此替代关键字。指定的键将覆盖 Oracle GoldenGate 找到的任何现有主键或唯一键。
防止密钥更改
在 Oracle GoldenGate 开始从表中提取数据后,请勿向密钥添加列。此规则适用于主键、唯一键、KEYCOLS 键或全列键。Db2 LUW 没有为添加到表的列提供之前的映像。如果在源上更新了密钥中的任何列,则在复制更新时,Oracle GoldenGate 需要先于映像与目标表中的当前值进行比较。
维护实体化查询表
要维护源实体化查询表与目标实体化查询表 (MQT) 之间的奇偶校验,请复制基表,但不复制 MQT。目标数据库根据 Replicat 应用到基表的更改来维护 MQT。
下面是配置这些表的规则:
-
在
TABLE和MAP语句中包含基表。 -
请勿在
TABLE和MAP语句中包含 MQT。 -
通配符可以在
TABLE和MAP语句中使用,即使它们可以解析 MQT 名称和常规表名。Oracle GoldenGate 会自动从通配符表列表中排除 MQT。但是,在 ExtractTABLE语句中按名称显式列出的任何 MQT 将导致 Extract 异常终止。
创建时间表
时间表是一个表,用于维护其数据的历史记录以及其数据有效的时段。Oracle GoldenGate 中使用期间表来跟踪表中删除或更新的所有旧行。时间表还用于维护其行和数据的业务有效性。例如,Oracle GoldenGate 会跟踪行有效的时间段。有三种类型的时间表:系统期间表、应用程序期间表和位时间表。
转换为时间表
可以将已经存在的表转换为时间表,时间表会更改表的结构。本节介绍表的结构如何更改。以下示例现有表已转换为本部分示例中的所有三种时间表类型:
Table policy_info
(
Policy_id char[4] not null primary key,
Coverage int not null
)
And the tables contains the following initial rows
POLICY_ID COVERAGE
------------- -----------
ABC 12000
DEF 13000
ERT 14000
示例 1 将现有表转换为系统期间时间表
通过添加 SYSTEM_PERIOD、transaction id 列和 SYSTEM_TIME 期间,可以将示例现有表转换为系统期间时间表,如下所示:
ALTER TABLE policy_info
ADD COLUMN sys_start TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW BEGIN;
ALTER TABLE policy_info
ADD COLUMN sys_end TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW END;
ALTER TABLE policy_info
ADD COLUMN ts_id TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS TRANSACTION START ID;
ALTER TABLE policy_info ADD PERIOD SYSTEM_TIME(sys_start, sys_end);
然后,使用以下两种方法之一为新时间表创建历史记录表:
CREATE TABLE hist_policy_info
(
policy_id CHAR(4) NOT NULL,
coverage INT NOT NULL,
sys_start TIMESTAMP(12) NOT NULL ,
sys_end TIMESTAMP(12) NOT NULL,
ts_id TIMESTAMP(12) NOT NULL
);
ALTER TABLE hist_policy_info ADD RESTRICT ON DROP;
CREATE TABLE hist_policy_info LIKE policy_info with RESTRICT ON DROP;
RESTRICT ON DROP 子句不允许在删除系统期间时间表时删除历史记录表。否则,在删除关联的临时表时会隐式删除历史记录表。可以创建不带 RESTRICT ON DROP. 的历史记录表不能显式删除历史记录表。
创建历史记录表时不应使用 GENERATED ALWAYS 子句。此处系统期间时间表的主键也不适用,因为基表中特定行的更新可能很多,这会为同一组主键触发多个插入到历史记录表中。除此之外,历史记录表的结构应与其关联的系统期间时间表的结构完全相同。历史记录表的列数和列顺序必须与系统期间时间表相同。不能显式添加、删除或更改历史记录表列。必须将系统期间时间表与其历史记录表与其语句关联:
ALTER TABLE policy_info ADD VERSIONING USE HISTORY TABLE hist_policy_info.
表的 GENERATED ALWAYS 列是始终由数据库管理器填充的列,因此您无法控制这些列。数据库管理器会根据系统时间填充这些列。
额外添加的 SYSTEM_PERIOD 和 transaction id 列将具有现有行的默认值,如下所示:
POLICY_ID COVERAGE SYS_START SYS_END TS_ID
--------- ----------- -------------------------------- -------------------------------- -------------------------------------------------------------------------------
ABC 12000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
DEF 13000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
ERT 14000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
在开始更新时间表后,将使用之前的图像填充关联的历史记录表。
示例 2 将现有表转换为应用程序期间时间表
通过添加时间列和 BUSINESS_TIME 期间,可以将示例现有表转换为应用程序期间时间表,如下所示:
ALTER TABLE policy_info ADD COLUMN bus_start DATE NOT NULL DEFAULT '10/10/2001'"
ALTER TABLE policy_info ADD COLUMN bus_end DATE NOT NULL DEFAULT '10/10/2002'
ALTER TABLE policy_info ADD PERIOD BUSINESS_TIME(bus_start, bus_end)
添加时间列时,需要确保在输入现有时间列的业务有效性时间值时,bus_start 列的值始终小于 bus_end,因为这些列指定了行的业务有效性。
新的应用程序期间时间表类似于:
POLICY_ID COVERAGE BUS_START BUS_END
--------- ----------- ---------- -------------------------------
ERT 14000 10/10/2001 10/10/2002
DEF 13000 10/10/2001 10/10/2002
ABC 12000 10/10/2001 10/10/2002
示例 3 将现有表转换为时空表
通过添加 SYSTEM_PERIOD、时间列以及 SYSTEM_TIME 和 BUSINESS_TIME 期间,可以将示例现有表转换为时空表,如下所示:
ALTER TABLE policy_info
ADD COLUMN sys_start TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW BEGIN;
ALTER TABLE policy_info
ADD COLUMN sys_end TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW END;
ALTER TABLE policy_info
ADD COLUMN ts_id TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS TRANSACTION START ID;
ALTER TABLE policy_info ADD PERIOD SYSTEM_TIME(sys_start, sys_end);
ALTER TABLE policy_info ADD COLUMN bus_start DATE NOT NULL DEFAULT '10/10/2001'"
ALTER TABLE policy_info ADD COLUMN bus_end DATE NOT NULL DEFAULT '10/10/2002'
ALTER TABLE policy_info ADD PERIOD BUSINESS_TIME(bus_start, bus_end)
添加时间列时,必须确保在输入现有时间列的业务有效性时间值时,bus_start 列的值始终小于 bus_end,因为这些列指定了行的业务有效性。
然后,使用以下两种方法之一为新时间表创建历史记录表:
CREATE TABLE hist_policy_info
(
policy_id CHAR(4) NOT NULL,
coverage INT NOT NULL,
sys_start TIMESTAMP(12) NOT NULL ,
sys_end TIMESTAMP(12) NOT NULL,
ts_id TIMESTAMP(12) NOT NULL
);
ALTER TABLE hist_policy_info ADD RESTRICT ON DROP;
CREATE TABLE hist_policy_info LIKE policy_info with RESTRICT ON DROP;
-
RESTRICT ON DROP子句不允许在删除系统期间时间表时删除历史记录表。否则,在删除关联的临时表时会隐式删除历史记录表。可以创建不带RESTRICT ON DROP.的历史记录表不能显式删除历史记录表。创建历史记录表时不应使用
GENERATED ALWAYS子句。此处系统期间时间表的主键也不适用,因为基表中特定行的更新可能很多,这会为同一组主键触发多个插入到历史记录表中。除此之外,历史记录表的结构应与其关联的系统期间时间表的结构完全相同。历史记录表的列数和列顺序必须与系统期间时间表相同。不能显式添加、删除或更改历史记录表列。必须将系统期间时间表与其历史记录表与其语句关联:
ALTER TABLE policy_info ADD VERSIONING USE HISTORY TABLE hist_policy_info.
表的 GENERATED ALWAYS 列是始终由数据库管理器填充的列,因此您无法控制这些列。数据库管理器会根据系统时间填充这些列。
额外添加的 SYSTEM_PERIOD 和 transaction id 列将具有现有行的默认值,如下所示:
POLICY_ID COVERAGE SYS_START SYS_END TS_ID
--------- ----------- -------------------------------- -------------------------------- -------------------------------------------------------------------------------
ABC 12000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
DEF 13000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
ERT 14000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
在开始更新时间表后,将使用之前的图像填充关联的历史记录表。
附加的 SYSTEM_TIME 期间、事务处理 ID 和时间列将具有现有行的默认值,如下所示:
POLICY_ID COVERAGE SYS_START SYS_END TS_ID BUS_START BUS_END
--------- ----------- -------------------------------- -------------------------------- -------------------------------- ---------- -------------------------------------
ABC 12000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000 10/10/2001 10/10/2002
DEF 13000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000 10/10/2001 10/10/2002
ERT 14000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000 10/10/2001 10/10/2002
用户开始更新时间表后,将使用之前的图像填充历史记录表。
示例 4:异构环境中的复制。
在应用端没有时间表的异构配置中,只能复制系统期间表和位时间表,但不能复制关联的历史记录表。在这种情况下执行复制时,必须处理 SYSTEM_PERIOD 和事务 ID 列值。这些列将具有目标数据库可能不支持的一些值。您应首先使用映射转换函数将这些值转换为目标数据库支持的格式,然后相应地映射列。
例如,MySQL 的 DATETIME 范围从 1000-01-01 00:00:00.000000 到 9999-12-31 23:59:59.999999。无法将时间戳值 0001-01-01-00.00.00.000000000000 复制到 MySQL。要复制此类值,必须将此值转换为 MySQL DATETIME 值 1000-01-01 00:00:00.000000,然后映射列。如果 policy_info 系统期间表中包含以下行:
POLICY_ID COVERAGE SYS_START SYS_END TS_ID
--------- ----------- -------------------------------- -------------------------------- -------------------------------------------------------------------------------
ABC 12000 0001-01-01-00.00.00.000000000000 9999-12-30-00.00.00.000000000000 0001-01-01-00.00.00.000000000000
要将行复制到 MySQL 中,可以使用 colmap() 函数:
map *source_schema*.policy_info, target *target_schema*.policy_info colmap
(policy_id=policy_id, coverage=coverage, sys_start= @IF( ( @NUMSTR( @STREXT(sys_
start,1,4))) > 1000, sys_start, '1000-01-01 00.00.00.000000'), sys_end=sys_end,
ts_id= @IF( ( @NUMSTR( @STREXT(ts_id,1,4))) > 1000, ts_id, '1000-01-01
00.00.00.000000'));
使用期间表复制
可以选择以下方法之一来复制系统期间或位时间表,如下所示:
-
只能将临时表复制到另一个临时表;这是默认行为。Oracle GoldenGate 不会复制
SYSTEM_TIME期间和事务处理 ID 列,因为这些列是在应用端自动生成的。数据库管理器使用系统时钟时间和默认值填充目标时间表中的列。您可以保留这些列的原始值,然后使用以下任一项:-
在目标时间表中添加额外的时间戳列并相应地映射这些列。额外的列将自动添加到关联的历史记录表中。
-
在应用端使用非时间表,并相应地映射列。在此方案中,您将无法维护历史记录表。
-
在源为 Db2 LUW 且目标为其他数据库的异构配置中,您可以忽略自动生成的列,也可以使用适当的列转换函数以目标数据库支持的格式转换列值,并相应地将其映射到目标列。
或者
-
-
可以将时间表与关联的历史记录表分别复制到时间和历史记录表,然后必须指定复制参数
DBOPTIONS SUPPRESSTEMPORALUPDATES。必须同时指定要在提取参数文件中捕获的时间表和历史记录表。Oracle GoldenGate 将复制SYSTEM_TIME期间和事务处理 ID 列值。您必须确保数据库实例具有在应用端运行存储过程的执行权限。
在使用默认复制时,Oracle GoldenGate 无法检测和解决冲突,因为 SYSTEM_TIME 期间和 transactionstart id 列保持自动生成状态。不能在 set 和 where 子句中指定这些列。如果使用 SUPPRESSTEMPORALUPDATES 参数,则 Oracle GoldenGate 支持 CDR。