转换组
下面让我们通过一个例子,看看转换函数和转换组的概念,以及它们的应用情况。DB2 Spatial Extender 提供了四个转换组。每一个转换组都包含一个将几何图形转换成外部表现形式的函数和一个将外部表现形式转换成几何图形的函数。这四个转换组支持下面几种数据格式:
- ST_WellKnownText
在几何图形和相应的已知文本表现形式(well-known text,WKT)之间转换。WKT 以文本数据的形式保存在 CLOB 中,最大长度为 2GB。ST_AsText 方法用于将几何图形转换为 WKT。 - ST_WellKnownBinary
在几何图形和相应的已知二进制(well-known binary,WKB)表现形式之间进行转换。WKB 以二进制数据的形式存储在 BLOB 中,最大长度为 2GB。ST_AsBinary 方法可用于将几何图形转换成 WKB。 - ST_GML
在几何图形和对应的地理标记语言(Geography Markup Language,GML)之间进行转换。GML 以文本数据的形式保存在一个 CLOB 字段中,最大长度为 2GB。ST_AsGML 方法可用于将几何图形转换成 GML。 - ST_Shape
在几何图形和对应的 ESRI Shape 表现形式之间进行转换。Shape 以二进制数据的形式存储在一个 BLOB 字段中,最大长度为 2GB。ST_AsShape 方法可用于将几何图形转换成 Shape。
从外部表现形式(WKT、WKB、GML、Shape)转换成相应的几何图形并存储在 SQL 数据库中的过程是由 ST_Geometry、ST_Point、ST_LineString、ST_Polygon、ST_GeomCollection、 ST_MultiPoint、ST_MultiLineString 以及 ST_MultiPolygon 等构造函数实现的。每一个构造函数都经过重载,既可以接受 BLOB,也可以接受 CLOB 作为输入参数。根据输入数据的不同,这些构造函数可以决定您提供的到底是何种格式,然后对数据进行恰当的编码。
转换组的使用方法用 清单1中的 SQL 代码就很容易解释明白。
清单 1. 使用转换组 |
从上面的清单中可以看出,SELECT 语句取出表 T 中的所有字段。字段 G 声明的类型是 ST_Point,这是一种结构类型。很显然,当我们取出这些字段中存储的结构化数据时,需要对其进行转换。这个查询中并没有显式调用任何转换函数,但是 DB2 能够识别出这种结构化的数据,而且能够根据 CURRENT DEFAULT TRANSFORM GROUP 这一特殊注册项的设置来决定使用哪个转换组和转换函数。在第一个查询中,DB2 发现转换组指定为 ST_WellKnownText。该组中的 FROM SQL 转换函数是 ST_AsText()。这样,DB2 就调用 ST_AsText() 函数,将字段 G 中的所有结构化值转换成 CLOB。DESCRIBE 语句的输出能够证明这一点。当数据被取出的时候,这些 CLOB 值就和 ID 字段的值联系在了一起。
作为本节的结论,我们之所以要在空间数据中应用转换的概念,是因为我们想使从一个数据库向另一个数据库传输结构化数据的过程更加高效。然而,复制工具并不直接支持转换组和转换函数。因此,我们使用了一种更加手工化的方法。在视图的帮助下,我们将结构化数据转换为外部的表现形式,逆转换也是由视图和 INSTEAD OF 触发器一起实现的。下面两节将就这一点进行详细讨论。
捕获空间数据的变化
DB2 Replication 支持 LOB 的复制,空间数据也可以用转换组中的转换函数转换为 LOB。这些特性结合在一起,就能够直接支持空间数据的复制。在本节中,我们将解释如何对源表进行设置,以实现将空间数据转换为 LOB,并讨论 Capture 进程的功能。设置目标表的过程和 Apply 进程的功能将在下一节讨论。
转换组的概念通常用于在 DB2 数据库服务器和 DB2 客户机之间传送数据,在两个数据库之间传送数据也适用相同的概念。现在,源数据库变成了数据库客户机,它将数据提供给目标数据库(即数据库服务器)并存储在其中。从这个角度来看,这正是经典的客户机/服务器环境。
选择一种转换方式
前面已经讲过,我们在复制空间数据的时候可以选择不同的外部数据格式。为了确定正确的转换函数,我们需要制定下面的标准:
- 在源数据库和目标数据库上应该只需要很少的附加磁盘存储空间,或根本不需要。
- 转换过程应该尽可能快速执行,以避免对复制过程的整体性能产生影响。
为了同时支持这两项标准,我们既可以实现自己的转换组,也可以使用 DB2 Spatial Extender 已经提供的转换组。我选择使用已有的转换组 ST_WellKnownBinary,因为预定义转换组的功能经过了很好的测试,比起自己实现来可以降低成本。
选择文本形式还是二进制形式同样十分简单。文本形式通常比二进制形式更长,因为对于每一个浮点数而言,文本形式需要更多的字符才能表示。二进制数据的又一优点在于其更高的正确性。空间数据中的点是用符合 IEEE 754 标准的浮点数来存储的。将二进制数据用文本数据表示则牵扯到转换,会引入数据舍入的问题。因此,我们可能会降低已经存在于复制源中的数据的准确性,而且在目标数据库中重新构造二进制数据的过程又会进一步降低准确性。直接传输二进制数据就可以避免第二个问题。
根据前面的观察,转换组 ST_WellKnownBinary 和 ST_Shape 成为我们可能的选择。进一步观察 ESRI 的 shape 格式可以发现,shape 格式无法识别几何图形是只由一个部分组成的具有多个部分的几何形状,比如 multipoint(10 10),还是单纯的只有一部分的几何形状,如 point(10 10)。因此,如果任何类型的几何图形存储在这张待复制的表中,那么特定的类型信息就可能在复制过程中丢失掉。然而,如果我们知道空间数据具有某种更加专用的类型,那么这个参数是不适用的。只有在目标表上使用适当的构造函数才能保证重新构造出正确的专用类型。
已知二进制格式对于大型系统而言还有一个优势。这种格式既支持小型编码也支持大型编码。而 shap 格式将所有的信息都存储在小型编码中(每一条记录的头部除外),因此,就需要将每一个浮点数从大型编码转换到小型编码。
在另一方面,已知二进制格式还有一个缺点,即它比 shape 格式稍微冗余一些。它用于表示几何图形所需的字节数要多出几个。因此,我们并不强制使用 ST_WellKnownBinary,而放弃 ST_Shape,因为这两个转换组都能够有效地实现相同的目标。
不过,DB2 的复制并不直接支持 DB2 的转换组机制。 它不允许用户在从源表取出数据或向目标表插入数据时定义某个组。 复制工具只能将空间字段识别为一种不支持的类型。结果是我们必须在复制过程开始处理空间数据之前手工将其转换。
这一限制的确带来一些不便,但并不能阻止我们复制空间数据。我们将基于源表定义一个视图,让从空间数据到外部格式的转换在这个视图中进行。以这种方式创建的视图现在可用作订阅组中的复制源。
在复制 LOB 数据的时候,LOB 不会存储在 CD 表或 CD 视图中。而是只有更新指示器存储于其中。更新指示器可以供 Apply 进程使用,用于确定是否对 LOB 字段执行了更新操作。如果该字段未被更新,那么就没有必要将 LOB 的值从源表拷贝到目标表中。这种方法可以避免不必要的数据移动。
请您注意,插入操作总是会引起 LOB 数据的拷贝,因为 LOB 数据是新记录的一部分,目标表中并不存在。出于我们将要在视图中实现的手工格式转换过程,CD 表中并不存在与源表对应的更新指示器。前面提到,复制工具本身并不会把空间字段看成是一个可以复制的字段。结果导致我们必须自己提供并维护这样一个指示器字段。
视图的定义以及附加的更新指示器字段导致我们的方法分为四步,现在我们将概述其要点,并举出示例。假设我们打算复制 清单2中定义的表中的所有数据,包括空间数据。
清单 2. 定义要复制的源表 |
定义更新指示器
第一步是增加一个字段充当更新指示器,以及两个维护该字段的触发器。一个触发器用于在每次对记录进行更新时重置指示器。第二个触发器负责在当且仅当对几何图形字段进行更新时给指示器赋值。触发器是根据其定义的顺序触发的,也就是说,CREATE_TIME 较早的触发器会比在其之后定义的触发器先激活。由于我们希望先重置指示器,再在几何图形字段更新时对其赋值,因此我们必须当心触发器的执行顺序。必须先创建重置指示器的触发器,然后再创建更新指示器的触发器。 清单3中的 SQL 语句显示了必要的修改操作,以及按正确的顺序定义触发器的情况。
清单 3. 为空间字段增加更新指示器 |
在源表上创建视图
为了让所有的数据都具有适合于复制的正确格式,我们需要在源表上定义一张视图。这张视图的定义将涉及源表中所有需要复制的字段。源表中有两个空间字段。如前所述,空间字段需要转换成已知二进制格式。ST_AsBinary 函数可用于实现这一转换。更新指示器是另一个未在视图定义中出现的字段。我们并不想复制更新指示器;这个字段只在 Apply 进程决定来自空间字段的数据是否需要复制的时候才是有用的。因此,我们用 清单4中所示的 SQL 语句来创建基于复制源表的视图。
清单 4. 创建将空间数据转换成 BLOB 的视图 |
请注意,您在视图定义中应该总是用完全限定性的表名和对应的字段名,这样复制工具才能成功解析其定义,并析取出后面所需的相应信息。
创建视图和向源表中增加更新指示器的顺序无关紧要。这两个步骤都可以完全独立地进行。然而,后续步骤则要求必须完成前面这一步。
将源表注册为复制源
现在所有的准备工作都已完成,我们可以开始设置实际的复制环境了。当从视图进行复制时,DB2 复制机制要求将视图所基于的表也注册为复制源表。否则,我们就无法利用 Capture 进程来扫描日志文件,找出所有被修改且需要复制的记录。这意味着我们只能在目标数据库中对被复制的表进行完全刷新。而这在很多情况下显然不可行。
下面,我们假设您已经创建了捕获控制表(capture control table),也为数据库启用了复制功能。启用复制要求数据库配置参数 LOGRETAIN 设为 YES。请注意,您必须在修改了 LOGRETAIN 参数之后备份数据库。
注册源表的方法很简单。我们需要捕获除空间字段之外,且包括更新指示器在内的所有字段上的变化。 图6显示在 DB2 Replication Center 中注册源表的情况。您从这张图中可以看到,TRACK 字段的任何变化都不会被捕获,因为它是具有结构化类型的字段。
![]() |
注册过程创建了一张新的变化数据表(即 CD 表),Capture 进程用这张表记录从 DB2 日志中挖掘出来的 STREETS 表上发生的任何变化。让我们快速验证一下这一点。 清单5显示了几条 SQL 语句,先对 STREETS 表中的数据进行了修改,然后查询 CDSTREETS 表,看是否已经捕获并组装好正确的数据。请您注意,可能要等待一段时间之后 Capture 进程才能从日志中取得数据填入 CD 表中。
