分类:
2008-04-24 10:43:11
我们首先在未聚集的数据上运行一个查询,然后在聚集的数据上运行查询。两个场景之间的REORG TABLE 步骤将建立聚集顺序。为了确保能得到有意义的结果,我们还像 后面一个小节 中解释的那样,检验网格索引是否真正被用于这个查询。由于数据量比较小,前后两个查询在执行时间上测量不到明显的差别。但是这里收集了一个快照,并提取了关于表空间 USERSPACE1 的有趣信息,以突出两者之间的差别。像平常一样,从 shapefile 文件 europe/roads.shp 导入表中的数据,然后将 inline length 设为 2000。测量的确切的开关列在 SQL 脚本 test_clustering.sql 中,该脚本可以在 下载 一节中找到。
清单 9. 测试聚集空间数据的效果
$ db2se import_shape testdb -fileName /home/stolze/europe/roads -srsName WGS84_SRS_1003 -tableName roads -createTableFlag 1 -spatialColumn shape -typeName ST_LineString -inlineLength 2000 -idColumn id -commitScope 1500 GSE0000I The operation was completed successfully. $ db2 connect to testdb $ db2 "CREATE INDEX roads_grid_index ON roads(shape) EXTEND USING db2gse.spatial_index(0.27, 0.54, 1.6)" $ db2stop force && db2start $ db2batch -d testdb -f test_clustering.sql -i complete -s on --------------------------------------------- Statement number: 1 SELECT id FROM roads WHERE db2gse.ST_Intersects(shape, db2gse.ST_LineString( 'linestring(10 50, 20 40)', 1003)) = 1 SELECTIVITY 0.00000001 *** Tablespace Snapshot *** Tablespace Name = USERSPACE1 Buffer pool data logical reads = 13161 Buffer pool data physical reads = 1949 Total buffer pool read time (ms) = 39 --------------------------------------------- $ db2 connect to testdb $ db2 -td@ -f zvalue_fct.sql $ db2 -td@ -f zvalue_clustering_setup.sql $ db2stop force && db2start $ db2batch -d testdb -f test_clustering.sql -i complete -s on --------------------------------------------- Statement number: 1 SELECT id FROM roads WHERE db2gse.ST_Intersects(shape, db2gse.ST_LineString( 'linestring(10 50, 20 40)', 1003)) = 1 SELECTIVITY 0.00000001 *** Tablespace Snapshot *** Tablespace Name = USERSPACE1 Buffer pool data logical reads = 13161 Buffer pool data physical reads = 749 Total buffer pool read time (ms) = 16 --------------------------------------------- |
您会注意到,在聚集场景中,与未聚集的表相比,数据物理读操作的次数有了明显的降低 —— 只有之前的 38%。这个差别完全归功于聚集的影响,换句话说,在物理层面上,相关数据存储在临近的位置,使得在执行查询期间需要访问的数据页更少。
使用 Hilbert 空间填充曲线
基于空间属性的聚集在一些客户站点上已经被证明是非常有效的。当然,您可以设想用不同的方法来为生成的聚集列提供值。例如,可以按照网格索引的思想,使用与几何图形重叠的一个网格单元的标识符。而且,采用的方法很大程度上取决于拥有的空间数据。对于大地数据,由于地区表面具有封闭的特性,因此空间填充 Z 顺序曲线可能不是最好的选择。
为了方便,我们在 下载 一节中提供了另一种空间填充曲线,即 Hilbert 曲线的实现(请参阅 参考资料 一节以了解关于 Hilbert 曲线的信息)。研究表明,Hilbert 曲线可以很好地保存拓扑信息,甚至优于 Z 顺序曲线。然而,使用 Hilbert 曲线时要求编译用 C 编写的用户定义函数,并将它注册到数据库。这个编译可以在bldrtn 脚本的帮助下进行,该脚本可以在 sqllib/samples/cpp 目录中找到。在 hilbert_fct.sql 文件中可以找到用于注册函数的 SQL 语句。
添加一个有索引的聚集列的步骤非常类似于清单 8 中展示的步骤。但是,这一次我们可以使用一个生成的列,因为在函数computeHilbertVal 的定义中没有出现子选择,并且没有违反生成的列上的其他约束。清单 10 展示了这些特定的步骤,在将computeHilbertVal 函数注册到数据库之后便可以执行这些步骤。您会注意到,我们直接访问空间数据类型ST_Geometry 的 4 个属性,以避免陷入生成的列的麻烦当中。只有当被授予必要的权限,并且不使用大地坐标系时才能访问那些属性,因为在使用大地坐标系时,由于对大地情况中的属性的不同使用,将导致不准确的结果。但是,如前所述,在任何情况下,应该为大地数据选用一个不同的聚集标准。只有当表已经包含一些数据,并且想强制地为已有的行生成 hilbert 值的时候,两个SET INTEGRITY 语句才是必要的。相同的步骤同样也收集在 hilbert_clustering_setup.SQL 脚本中。必须确保有足够用于生成过程的日志空间。
清单 10. 用 Hilbert 值列扩展表
SET INTEGRITY FOR roads OFF@ ALTER TABLE roads ADD COLUMN hilbert_value BIGINT GENERATED ALWAYS AS ( computeHilbertVal( (shape..xMin + shape..xMax) / 2, (shape..yMin + shape..yMax) / 2, -180, 1000, -90, 1000) )@ SET INTEGRITY FOR roads IMMEDIATE CHECKED FORCE GENERATED@ CREATE INDEX hilbert_value_idx ON roads(hilbert_value)@ REORG TABLE roads INDEX hilbert_value_idx@ |
现在我们重复清单 9 中的操作。这里只显示聚集情况下的结果,因为未聚集的表产生的结果与之前是相同的。结果表明,Hilbert 曲线的确能够更好地根据拓扑聚集数据,与 Z 排序相比,它可以减少 1.5% 的数据物理读。如前所述,如果您不想自己将源代码编译到一个共享库中,那么使用 Hilbert 曲线可能不是好的选择。