分类:
2008-04-24 10:42:41
根据某个属性聚集数据是一种常见的、也是非常有用的技术,这种技术可以物理地组织一个表的数据。通过对底层的观察可以发现,具有相似值的数据常常一起被访问。所以,可以将类似的数据存储在接近的位置,使得对那些数据的访问不必分散到表空间中很多不同的页上,而是分布在临近的几个页上。根据空间数据的空间属性或几何图形间的距离聚集空间数据是很自然的。空间查询是展示局部数据访问(换句话说,现实中临近的几何图形常常被一起访问)的最好例子之一。例如,如果您看一个城市的街道地图,那么很可能对那个城市的所有街道感兴趣,而对地区另一边某个其他城市的街道不感兴趣。所以在物理上将那个城市的一些行存储在相邻的位置的确很有意义。
在 DB2 中建立数据聚集属性的方法是根据一个索引对表进行重组。然而,如果由于空间索引的复杂性质导致 DB2REORG TABLE 命令不理解空间索引,事情就不会那么容易了。关于这个问题有一个容易的方法,即使用一个列,这个列的值是根据涉及的图形计算的。这个列上声明的数据类型必须保证 DB2 能在这个列上创建一个本地 B- 树索引。这里使用空间填充曲线来保存空间和拓扑属性(请参阅 参考资料 一节,找到 H. Sagan 撰写的书籍)。我们在几何图形上取一个点,即形心点, 计算那个点在空间填充曲线上的值,并将结果存储在一个附加的列中。最后,在附加列上创建一个索引,并根据那个索引对表进行重组。
定义聚集列
在实际扩展这个包含空间数据的表并添加聚集列之前,必须定义一个函数,这个函数计算几何图形的形心点在空间填充曲线上的值。幸运的是,DB2 Spatial Extender 已经提供了大部分的逻辑,我们只需根据自己的目的将它们组合到一起。首先,有一个为多边形定义的方法ST_Centroid。将这个方法应用到ST_Envelope(对于任何非空的几何图形,它总是返回一个多边形)的结果上将得到我们需要的那个点。接下来就是基于 Z 顺序的索引机制的键生成器函数,该函数是 DB2 Spatial Extender 自带的(请参阅 参考资料 一节,了解关于 Index Extensions 的信息)。Z 顺序实际上是一种空间填充曲线 —— 这与我们想象的一样。关于键生成器函数的信息可以通过db2look 工具或直接从 DB2 编目视图获得。键生成器如清单 5 中定义的那样。
清单 5. Z 顺序索引的键生成器函数
CREATE FUNCTION db2gse.GseZordIdxKeyGen ( srsId INTEGER, xMin DOUBLE, xMax DOUBLE, yMin DOUBLE, yMax DOUBLE, xOffset DOUBLE, xScale DOUBLE, yOffset DOUBLE, yScale DOUBLE ) RETURNS TABLE ( coordsysId INTEGER, zValue BIGINT ) SPECIFIC ST_ZixKeyGen EXTERNAL NAME 'db2gsefn!gseZOrderIndexKeyGenerator' ...@ |
现在我们可以创建一个附加的函数,该函数将组合之前提到的函数,并为任何给定的几何图形产生空间填充 Z 曲线上的标量值。最终得到的computeZValue1 函数定义如清单 6 所示,在 下载 一节中的 zvalue_fct.sql 文件中也可以找到该函数。该函数以一个几何图形作为输入,另外还带有 4 个参数,这 4 个参数定义如何将点几何图形的 X 和 Y 维上的浮点坐标转换成用于计算 Z 值的整数值。当然,如果您不需要更多的灵活性,那么可以在函数主体中直接使用常量,而不是参数。注意,按照 DB2 Spatial Extender 范例,在乘上比例系数之前,浮点值要减去偏移量。清单 6 中的第二个函数computeZValue 是第一个函数的变种。它使用一种不同的方法为db2gse.GseZordIdxKeyGen 函数提供输入参数。外壳的计算和外壳形心的提取需要在 DB2 引擎与 Spatial Extender 之间进行通信。通过添加ST_MinX、ST_MaxX、ST_MinY 和ST_MaxY 方法,提取几何图形的最小和最大 X 和 Y 坐标,并直接计算形心,可以避免这种通信。
CREATE FUNCTION computeZValue1 ( g db2gse.ST_Geometry, xOffset DOUBLE, xScale DOUBLE, yOffset DOUBLE, yScale DOUBLE ) RETURNS BIGINT LANGUAGE SQL DETERMINISTIC NO EXTERNAL ACTION RETURN SELECT t2.zValue FROM TABLE ( VALUES (g..ST_Envelope()..ST_Centroid()) ) AS t1(p), TABLE ( db2gse.GseZordIdxKeyGen ( p..ST_SrsId(), p..ST_X(), p..ST_X(), p..ST_Y(), p..ST_Y(), xOffset, xScale, yOffset, yScale ) ) AS t2@ CREATE FUNCTION computeZValue ( g db2gse.ST_Geometry, xOffset DOUBLE, xScale DOUBLE, yOffset DOUBLE, yScale DOUBLE ) RETURNS BIGINT LANGUAGE SQL DETERMINISTIC NO EXTERNAL ACTION RETURN SELECT zValue FROM TABLE ( db2gse.GseZordIdxKeyGen ( g..ST_SrsId(), (g..ST_MinX() + g..ST_MaxX() / 2), (g..ST_MinX() + g..ST_MaxX() / 2), (g..ST_MinY() + g..ST_MaxY() / 2), (g..ST_MinY() + g..ST_MaxY() / 2), xOffset, xScale, yOffset, yScale ) ) AS t@ |
清单 7. 比较生成 Z 值的函数
$ db2se import_shape testdb -fileName /home/stolze/europe/roads -srsName WGS84_SRS_1003 -tableName roads -createTableFlag 1 -spatialColumn shape -typeName ST_LineString -idColumn id -commitScope 1500 GSE0000I The operation was completed successfully. $ db2batch -d testdb -f test_zvalue_fct.sql -i complete -s on --------------------------------------------- Statement number: 1 SELECT computezValue1(shape, -180, 1000, -90, 1000) FROM roads Prepare Time is: 0.000 seconds Execute Time is: 5.737 seconds Fetch Time is: 106.706 seconds Elapsed Time is: 112.443 seconds --------------------------------------------- Statement number: 2 SELECT computezValue(shape, -180, 1000, -90, 1000) FROM roads Prepare Time is: 0.000 seconds Execute Time is: 0.130 seconds Fetch Time is: 2.702 seconds Elapsed Time is: 2.832 seconds --------------------------------------------- Summary of Results ================== Elapsed Agent CPU Rows Rows Statement # Time (s) Time (s) Fetched Printed 1 112.443 101.000 110979 0 2 2.832 2.560 110979 0 |
最后一步是扩展表,使表根据几何图形的拓扑信息组织数据。我们假设有一个名为 ROADS 的表,这个表是在 shapefile 文件 europe/roads.shp 的基础上创建的。第一个想法可能是添加一个新的列,并使用GENERATED ALWAYS AS ( ... ) 语法来填充和维护它。但是,该函数的两个变种都使用子选择(第一个版本中的空间函数使用一个便笺式存储器来存放前后两个调用之间传递的信息),并违反了生成的列的某些约束。所以我们必须像清单 8 那样借助于触发器。为了确保所有已有的行都得到适当的处理,运行UPDATE 语句。按照空间属性聚集这些行的效果取决于在查询时对一个数据子集的访问。如果使用表扫描,那么聚集就不会真正有益,因为 DB2 仍然必须读取所有的行,那么物理排序不很重要了。所以我们创建一个空间网格索引,这个索引将在查询时用到。所有步骤同样可以在附带的 zvalue_clustering_setup.sql 文件中找到。
清单 8. 通过 Z 值列扩展表
ALTER TABLE roads ADD COLUMN z_value BIGINT@ CREATE INDEX z_value_idx ON roads(z_value)@ CREATE TRIGGER roads_zval_insert NO CASCADE BEFORE INSERT ON roads REFERENCING NEW AS n FOR EACH ROW MODE DB2SQL SET n.z_value = computeZValue(n.shape, -180, 1000, -90, 1000)@ CREATE TRIGGER roads_zval_update NO CASCADE BEFORE UPDATE OF shape ON roads REFERENCING NEW AS n FOR EACH ROW MODE DB2SQL SET n.z_value = computeZValue(n.shape, -180, 1000, -90, 1000)@ UPDATE roads SET z_value = computeZValue(shape, -180, 1000, -90, 1000)@ REORG TABLE roads INDEX z_value_idx@ |