服务器 频道

在DB2 UDB中复制空间数据(下篇)

  【IT168 服务器学院】 清单 11. 验证全部设置

INSERT
INTO   streets(id, name, track)
VALUES ( 1, ''first street'',
   db2gse.ST_LineString(''linestring(10 10, 20 20)'', 1) )@

        SELECT id, VARCHAR(name, 20),
       VARCHAR(track..ST_AsText(), 50)
FROM   tg_streets@
ID          2                    3
----------- -------------------- ------------------------------------------------------------
          1 first street         LINESTRING(10.000000 10.000000, 20.000000 20.000000)
  1 record(s) selected.

INSERT
INTO   streets(id, name, track)
VALUES ( 2, ''second street'',
   db2gse.ST_LineString(''linestring(10 15, 20 15)'', 1) )@

        SELECT id, VARCHAR(name, 20),
       VARCHAR(track..ST_AsText(), 50)
FROM   tg_streets@
ID          2                    3
----------- -------------------- ------------------------------------------------------------
          1 first street         LINESTRING(10.000000 10.000000, 20.000000 20.000000)
          2 second street        LINESTRING(10.000000 15.000000, 20.000000 15.000000)
  2 record(s) selected.

DELETE
FROM   streets
WHERE  id = 1@

        SELECT id, VARCHAR(name, 20),
       VARCHAR(track..ST_AsText(), 50)
FROM   tg_streets@
ID          2                    3
----------- -------------------- ------------------------------------------------------------
          2 second street        LINESTRING(10.000000 15.000000, 20.000000 15.000000)
  1 record(s) selected.

UPDATE streets
SET    name = ''another name''
WHERE  id = 2@

        SELECT id, VARCHAR(name, 20),
       VARCHAR(track..ST_AsText(), 50)
FROM   tg_streets@
ID          2                    3
----------- -------------------- ------------------------------------------------------------
          2 another name         LINESTRING(10.000000 15.000000, 20.000000 15.000000)
  1 record(s) selected.

UPDATE streets
SET (name, track) = ( ''yet another name'',
       db2gse.ST_LineString(''linestring(5 5, 1 1)'', 1) )
WHERE ID = 2@

        SELECT id, VARCHAR(name, 20),
       VARCHAR(track..ST_AsText(), 50)
FROM   tg_streets@
ID          2                    3
----------- -------------------- ------------------------------------------------------------
          2 yet another name     LINESTRING(5.000000 5.000000, 1.000000 1.000000)
  1 record(s) selected.
      

  上面的例子中并不包含任何针对 ID 字段的 UPDATE 操作。如果您希望对主键字段中的数据进行修改,或者,更确切地说,您希望对目标主键字段进行修改,那么您就需要先从定义目标主键的字段获取其先前的值。否则,Apply 进程就无法将在源表中修改的记录与相应的目标表记录匹配起来。有关这方面的更多细节请参考 DB2 Replication User''s Guide and Reference [4]。

  设置工具 db2se_repl

我们详细看一看捕获空间数据的变化和准备目标数据库两节中必要的设置步骤。为了更进一步简化管理任务,我们用 Java 编程语言实现了一个名为 db2se_repl 的工具您用这个工具可以通过完全限定名及其所在的数据库对源表进行详细说明,也可以定义您打算将数据复制到哪张目标表上。

  语法

  这个工具的定义是基于语法的,下面您可以看到这种语法的详细情况,以及若干选项和关键字的含义。图中的语法图遵从 DB2 SQL Reference所使用的样式。


 
>>--SETUP SPATIAL REPLICATION------------------------------>
>----| source |--| target |--+------------------------+---><
                             -''-VERBOSE--+---------+---''
                                         -''-TRACE---''

source:
|--REPLICATE TABLE--+-----------------+--table_name-------->
                    -''-schema_name--.--''
>-----+---------------------------+------------------------>
      |     .--,------------.     |
      |     V               |     |
      -''-(-----column_name--+--)---''
>-----FROM CAPTURE SERVER--database_url-------------------->
>-----USER--user_name--PASSWORD--password------------------>
>-----+-----------------------------------------------+----|
      -''-USING--(--CAPTURE SCHEMA--capture_schema--)---''

target:
|--TO TARGET TABLE--+-----------------+--table_name-------->
                    -''-schema_name--.--''
>-----+---------------------------+------------------------>
      |     .--,------------.     |
      |     V               |     |
      -''-(-----column_name--+--)---''
>-----ON APPLY SERVER--database_url------------------------>
>-----+---------------------------------------+------------>
      -''-USER--user_name--PASSWORD--password---''
>-----USING--(--*---SUBSCRIPTION SET--set_name--*--,------->
>-----*--APPLY_QUALIFIER--apply_qualifier--*--,------------>
>-----*--SPATIAL REFERENCE SYSTEM IDENTIFIER--srs_id--*--)-|

  REPLICATE TABLE schema_name.table_name ( column_name, & )

定义待复制的源表及其字段。如果未指定字段名,那么表中的所有字段都将被复制。在所有字段中必须有且仅有一个空间类型的字段。字段清单中必须包含源表的主键。

  FROM CAPTURE SERVER database_url

定义可以找到源表的数据库的名称和位置。数据库的 URL 必须具备如下的格式:
//host-name:port/database-name
这项信息用于通过 Type 4 JDBC 驱动程序链接源数据库。这意味着您不必将数据库加入本地目录。

  CAPTURE SCHEMA capture_schema

定义源数据库上的 capture 模式。如果这项参数未指定,那么默认模式名称为“ASN”。

  TO TARGET TABLE schema_name.table_name (column_name, -'')

用限定性名称表示要复制到的目标表。如果该表不存在,则在目标数据库中基于源表的定义创建一个。在这里不指定字段名;字段名是根据源表派生出来的。

如果目标表已经存在,则重用,并且如果有指定的字段名,那么这些字段名必须和已经存在的表中的字段名相等。

  ON APPLY SERVER database_url

指定目标表所在的数据库的名称和位置。数据库的 URL 必须具备下面的格式:
//host-name:port/database-name
这项信息用于通过 Type 4 JDBC 驱动程序连接目标数据库。这意味着您不必非将这个数据库记录在本地目录中不可。

  SUBSCRIPTION SET set_name

指定一个订阅集合,源到目标的映射关系将作为新成员加入其中。

  APPLY QUALIFIER apply_qualifier

指定用于该订阅集合的应用限定符。

  SPATIAL REFERENCE SYSTEM IDENTIFIER srs_id

指定一个空间参照系的数字标识符。在将已知二进制数据转换成空间数据时将用到这个标识符。这个空间参照系必须已经存在于目标数据库上。
在这里使用的空间参照系(spatial reference system,SRS)最好和源数据库中的数据使用的 SRS 相同。
您必须至少保证源数据库和目标数据库使用的是相同的坐标系。否则,您的数据将表现在一个不同的坐标系中,本质上就会导致不同的数据。

  USER user_name PASSWORD password

定义用于链接源数据库或者目标数据库的用户名及口令。如果不为目标数据库提供用户名和口令,那么给源数据库提供的目标和口令将用于目标数据库。

  VERBOSE

将 asnclp 工具生成的所有消息都输出到标准输出设备上来。默认情况下这些消息是看不到的。

  TRACE

打开 asnclp 工具的跟踪机制。跟踪信息将写入标准输出流。

  处理逻辑

  这一工具的处理逻辑遵从 捕获空间数据的变化和准备目标数据库两节的描述。只有当源表尚未注册为复制表时才能对其进行设置。如果注册已经完成,系统会简单地重用以前的定义。如果不是这种情况,那么工具会向源表中加入更新指示器字段、创建源视图,以及注册源表和源视图,从而创建 CD 表与 CD 视图。

  在目标系统一方,工具也允许目标表已经存在。但是工具不会验证其字段和数据类型是否(与源表)匹配。如果目标表不存在,就创建一张。在这个阶段中我们也把源表的主关键字定义应用到目标表上。这个主关键字对于 INSTEAD OF 触发器的正常工作而言是必不可少的。带触发器的目标视图在订阅成员定义之前创建。

  工具用于创建视图和触发器的模式名为 DB2SE_REPL。请您注意,视图的非限定性名称与表的非限定性名称相同。这意味着用这种方法设置的表都必须具备惟一的非限定性名称;也就是说,如果您的两个不同模式中都有名为 TAB 的表,那么 db2se_repl 工具将无法成功为这两张表设置复制。

  复制专用的所有命令都是用 asnclp 工具执行的。因此,这个工具并没有在对空间数据的处理之上又实现什么特殊的逻辑。请注意,并不是 asnclp 的所有可能选项都被传递到 db2se_repl 的接口上。我们致力于实现一个简单的接口,它不具备丰富的特性。比如说,如果您想要调整订阅集合的时间安排,或改变其类型(默认条件下定义的是只读的订阅集合),那么您应该要么自己创建订阅集合,那么在 db2se_repl 创建好之后到 DB2 Replication Center 中对其进行适当的修改。

  示例输出

  捕获空间数据的变化和准备目标数据库这两节使用表 STREETS 进行复制。工具也能实现上面描述的相同步骤, 清单 12 向您展示了这个过程是如何完成的。在我们的例子中,我们用名为 src_DB 的数据库作为源数据库,目标数据库是 TGT_DB。表 STREETS 放置在源数据库的模式 S 和目标数据库的模式 T 中。输出信息为您简短地描述了设置的过程。

清单 12. 用 db2se_repl 设置 STREETS 的复制

db2se_repl "SETUP SPATIAL REPLICATION
REPLICATE TABLE s.streets(id, name, track)
FROM CAPTURE SERVER //localhost:50000/src_db
USER db2admin PASSWORD ibmdb2
TO TARGET TABLE t.streets
ON APPLY SERVER //localhost:50000/tgt_db
USER db2admin PASSWORD ibmdb2
USING ( SUBSCRIPTION SET sp_set, APPLY QUALIFIER
   apply_spatial, SRS ID 1 )"
Connecting to databases and checking setup...done.
Collecting defaults from database...done.
Extending source table with indicator column...done.
Creating replication view ''DB2SE_REPL.STREETS''...done.
Creating replication dummy view...done.
Registering source table and dummy view for replication...done.
Updating replication catalog...done.
Dropping dummy view...done.
Creating target table...done.
Creating replication view ''DB2SE_REPL.STREETS''...done.
Creating triggers on target view...done.
Creating subscription set ''SP_SET''...done.
Adding target view to subscription set ''SP_SET''...done.
Disconnecting from databases...done.
SER0000I  The operation was completed successfully.

  当成功执行设置之后,您可以启动 capture 和 apply 服务器,对源表 S.STREETS 中的空间数据或其他数据所作的所有修改都会被捕获到,并应用到目标表 T.STREETS 或者您定义的其他任何目标数据库上。您现在可以运行清单 11 中列出的那些测试,验证一下空间数据复制的设置是否能正常工作。

  说明

上面描述的复制空间数据的方法并没有提到 DB2 Spatial Extender 或 DB2 Replication 中所有各种不同的细节情况。现在让我们来看看其中的几个问题。

  并非复制问题 —— 地理编码 (geocoding)

  有一个非常重要的问题需要谈一下,您可能并不一定在所有的情况下都用上面描述的方法来复制空间数据。如果您的源表或目标表上具备地理编码器(geocoder)那么您可以从表中的其他字段,如地址字段等,再次生成空间数据。您可以对地址字段进行复制,这样就具备了对地址进行地理编码的全部必要信息,又可以生成相应的空间数据值。

  根据地址数据生成空间数据的过程称为地理编码。地理编码器就是实现了地理编码算法的一个函数。 DB2 Spatial Extender User''s Guide and Reference 中提供了一种架构,可以支持很多种不同的地理编码器。您也可以编写您自己的用户定义函数(user-defined function,UDF),将地址数据作为输入参数,将其转换成空间数据。地址数据可以是任何形式的非空间数据;它并不一定非得是“555 Bailey Ave. San Jose, CA 95141”这种真实世界中的地址。

  如果您把地理编码器和您的复制方案结合起来使用,以便不复制空间数据自身,那么您就会使用到如 图16 所示的一种设置。源表上有一个地理编码器,它根据同一张表中的地址数据生成空间数据 (1)。源表中包含着空间数据,访问源表的应用程序也可以使用这些空间数据。当把源表中的信息复制到目标表中时,您将复制包含地址数据的字段,但不复制空间数据字段 (2)。在目标数据库中,您再次使用地理编码器将地址数据转换成空间数据 (3)。地理编码必然在每一行数据上都发生两次:一次在源表上,另一次在目标表上。 图16总结了上面描述的这种设置。空间字段由蓝色标出,在源表上的地理编码、复制、在目标表上对地址数据的地理编码这三个不同的步骤已经被编上数字。

  图 16. 对复制得到的地址数据进行地理编码 

  在很多情况下,我们可能并不希望在目标表上对地址数据进行额外的地理编码操作。比如说,如果您使用了一个地理编码器,您就必须接受两次运行地理编码器带来的性能损失。另一个问题应该是,地理编码器可能不能对所有的地址进行编码。您可以为某些地理编码器不能处理的地址手工设置坐标。这种手工操作必须在复制数据上重复进行。此外,如果您使用[3] 中描述的 Web 服务,那么很可能对地理编码器本身的使用也是强制收费的。对同一地址在复制之后再次进行地理编码,这样会增加单个地址的处理费用。在这种情况下,本文中介绍的技术对您来说也许是一种可行的选择,当然它对管理和设置的要求也是较高的。

  请注意,如果您采用附加字段和触发器将空间数据转换成 LOB,类似地理编码器的方法也还是可以用的。触发器将重新产生附加字段的值(让我们称其为 SPATIAL_LOB 字段)。在对源表中的数据进行复制时,您也复制了 SPATIAL_LOB 字段中的数据。在目标表上,您将使用相同的方法,把复制过来的数据存储在一个单独的字段中。您可以再次使用触发器从复制过来的 LOB 生成空间数据。因为重新构造数据的时候使用的是空间函数,您可以简单地认为这些函数就是“地理编码器”,我们又一次面临上面已经解释过的情况。这种方法的缺点显然是要占用额外的磁盘空间,以及需要在源表的用户事务上执行到 LOB 的转换。我们提出的技术仅仅要求使用最小的磁盘空间(需要增加一个 CHAR(1) 字段),转换的工作量完全是由 Apply 进程处理的。

  空间字段的 INLINE LENGTH

  INLINE LENGTH 这方面的问题本文一直都没有提及。当创建表的时候,您应该考虑空间字段的 INLINE LENGTH 参数的定义。INLINE LENGTH 定义了结构化类型最大占据多少字节,在这个范围内结构化类型还是像 VARCHAR FOR BIT DATA 那样与一条记录的其他数据存储在一起。如果结构化的数值过长,就要像 BLOB 那样存储在一个与表相关联的长表空间中。INLINE LENGTH 越大,能与表中其余数据一起存储的(空间)数据就越多。

  像 VARCHAR FOR BIT DATA 那样存储结构化数据的好处显然在于,这样的值可以缓存在 DB2 的缓冲区池中,而 LOB 是直接从磁盘上读写的,I/O 量较大。

  复制中的可选项

  DB2 复制还提供了很多其他的选项,可以用来对复制机制进行控制。举例来说,您可以改变时间表,在复制过程中的某些特定点上运行额外的 SQL 语句,对订阅集合进行分组并指派不同的限定符,创建索引、过滤记录、指定表空间,等等。所有这些选项大都和本文描述的空间数据复制方法是正交关系。

  复制 LOB

  空间数据转换成 LOB、对 LOB 进行复制、然后又在目标表上转换回空间数据。这种借用 LOB 的方法意味着复制 LOB 时需要考虑的特殊问题在复制空间数据时同样需要考虑。比如说,Apply 进程会从源表中选择最新版本的空间数据。这个版本可能和 CD 表中获得的记录中的其他数据并不是同一版本,这种不一致的情况在下一次 Apply 周期中将会得到修正,但是您应该了解这种可能性。

  结束语

  本文向您展示了一种利用 DB2 UDB V8.1 和 DB2 Replication 复制空间数据的方法。我们遵从已有的技术,用一张基于源表的视图将空间数据转换成外部数据格式(在我们的例子中是二进制)。相应的 CD 表和 CD 视图都需要作些许调整才能适应我们的需要。对源表进行适当的设置之后,Apply 进程就能以 BLOB 的形式捕获到空间数据发生的所有变化,并将其应用到目标视图上。再加上三个 INSTEAD OF 触发器,这张视图就相当于给 Apply 进程定义了一个操作的接口。触发器定义了逆向转换过程,从而再次构造出与源表中一样的空间数据。这一过程得到的结果是空间数据的一种无缝复制。我们详细地描述了如何设置源表和视图,以及目标表及其视图和触发器。

  为了进一步简化设置的任务,您可以使用 db2se_repl。这个工具能执行必要的 SQL 语句和复制命令,可用来创建表、视图及触发器,并可通过 asnclp 命令行接口发出必要的复制命令、执行复制功能。

0
相关文章