Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103677787
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-04-24 10:42:07

出处:51CTO.com整理  
 
DB2 内部对空间数据的处理

空间数据可能变得非常复杂,需要很多空间来存储一个几何图形中各个点的信息。例如,表示整个美国的区域的几何图形由 60 个多边形组成,总共有 198569 个点来定义那些多边形。按照 Spatial Extender 内部格式,这个几何图形的完整定义要使用 0.9 MB 的磁盘空间(使用了压缩)。如果几何图形按照 ESRI 几何图形格式编码,那么它实际上需要 3.1 MB 的磁盘空间(请参阅 参考资料 一节,了解关于 ESRI 几何图形格式的更多信息)。所有信息封装在一个ST_Geometry 值中,这意味着这个值在数据库中也需要大约 1 MB 的磁盘空间。另一个例子是只表示一个点的空间值。对于 X 和 Y 维,我们只有用于两个浮点值的 8 个字节。将一个点表示成ST_Point 值会增加一些开销,但是我们谈论时仍然当作是几个字节。

DB2 表中一个行中存储的所有值的总大小不能超过表空间的页宽。一个例外是大型对象(LOB),它最大可达 2 GB。DB2 支持的最大页宽是 32K。所以存储需要 1 MB 空间的几何图形需要类似于 LOB 的存储机制。但总是为点数据使用那种机制就过分了。为了解决千差万别的需求,DB2 实现了一种用于存储空间数据(或通常的结构数据)的混合方法。如果一个空间值超过了某个大小(即所谓的 inline length),那么这个值就被存储为 BLOB。否则,这个值就存储为 VARCHAR FOR BIT DATA 值。下一节 将详细讨论如何为空间列设置 inline length,以及通过更改设置可以获得的好处。之后,我们讨论 空间数据聚集,为 编写空间 SQL 查询、调优 空间网格索引 提供指南,最后我们解释如果经常要修改数据,则建议使用哪种表空间类型。

设置空间列的 inline length

在 上一节 中,我们解释了 DB2 存储需求多变的空间数据的内部机制。确定几何图形是存储为 VARCHAR FOR BIT DATA 还是 BLOB 的决定因素就是所谓的 inline length,这个参数适用于任何表中的空间列。如果空间值的内部表示需要的字节数少于 inline length 设置中指定的值,那么它将以 内联(inline) 的方式存储为 VARCHAR FOR BIT DATA。否则,这个值将被 大对象化(lobify),并在该表的 LONG 表空间中存储为 LOB。

inline length

当在数据库中创建一个新的结构类型时,DB2 将根据类型定义中指定的属性计算那个数据类型的缺省 inline length。可以在系统编目视图 SYSCAT.DATATYPES 的 INLINE_LENGTH 列上找到一个结构类型的缺省 inline length。如果在CREATE TABLE 或ALTER TABLE ... ADD COLUMN ... 语句中定义表的列时没有显式地指定 inline length,那么将沿用缺省值。

可以使用ALTER TABLE ... ALTER COLUMN ... SET INLINE LENGTH ... 语句修改(增加)已有空间列的 inline length。除非通过REORG TABLE 语句 加LONGLOBDATA 选项重组存储在表中的数据,否则这种修改只影响 DB2 编目和随后的数据修改。如果值的大小小于新的 inline length,那么这个重组过程将把大对象化的空间值转换成内联值。

应该记住,以内联方式存储数据比以大对象化方式存储数据要可取得多。原因是,内联的数据当作 VARCHAR FOR BIT DATA 对待。这个值与同一行中所有其他属性一起存储在一个数据页中。一旦数据存储在那样一个页上,那一页将通过缓冲池来访问,这样可以利用先进的缓存技术,从而尽量避免文件 I/O。而对于 LOB 则截然不同,它总是直接从磁盘读取。

所以经验法则非常简单:将 inline length 设置得尽可能高,以便让尽可能多的空间值以内联方式存储。当然,实际情况并不像看上去的那么简单。高的 inline length 值告诉 DB2 空间值实际上可以在单独一行中占用很多字节。每一行的最大大小要受到针对表定义的页宽和属性(列)的限制。例如,如果有一个页宽为 4 KB(4096)的表空间,那么一行的最大大小不能超过 4005 字节(请参阅 参考资料 一节,了解关于 SQL 限制的更多信息)。如果这个表有一个不能为空的 INTEGER 列和一个可以为空的 VARCHAR(100) 列,再加上一个空间列,那么最多可以将 inline length 设置为 4005 - 6 - 4 - (1+2+100) - 1 = 3891,其中 6 个字节用于行的前缀,4 个字节是 INTEGER 列需要的空间,(1+2+100) 个字节是为 VARCHAR(100) 预留的,最后 1 个字节用于空间列的 NULL 指示符(请参阅 参考资料 一节,找到关于数据库对象和 CREATE TABLE 语句的一本书)。可以看到,其他列的长度和 inline length 实际上是相互竞争的。为了进一步增加 inline length,可以将表放在页宽为 8K、16K 甚至 32K 的表空间上。这样,对于之前的例子,就可以分别将 inline length 设为 7987、16179 或 32563 字节。

选择适当的 inline length

在将所有空间数据存储到 32K 的表空间上并且将 inline length 设置成尽可能大的值之前,应该首先分析您的数据实际上有多大以及其他参数可能对页宽产生的影响。如果只有ST_Point 值,那么每个点将需要最多 245 字节的物理存储,如清单 3 所示。在这种情况下,甚至 减少 inline length 更有帮助,因为可以使用更小的页宽和/或在表中使用更多的列。但是要注意,ALTER TABLE 语句只允许增加 inline length。如果想使用更小的值,那么必须在创建表的时候指定。Spatial Extender 导入过程允许显式地为空间列指定 inline length。

在结构类型中嵌套 LOB

虽然points 属性被定义为 BLOB,但是 DB2 并不会单独地存储它。相反,整个几何图形信息(包括 BLOB 数据)都存储在一起 —— 至于存储为内联值还是大对象化值,则取决于列的 inline length。结构类型的实现使所有属性值并置到一个二进制流中,任何添加的必要的元信息和产生的二进制流在物化(也就是存储到一个表中)的时候,或者存储为内联值,或者存储为大对象化值。

这种方法使任何处理 LOB 的应用程序可以以内联方式存储短的 LOB 值,并利用 DB2 的缓冲池。

清单 3 展示了如何计算每个几何图形在以内联方式存储时需要多少磁盘空间。我们假设所有几何图形都存储在一个名为 SPATIAL_DATA 的表的 GEOMETRY 列中。第一个查询使用LENGTH 函数。该函数显示以内联方式存储的值的宽度。如果是大对象化的值,那么它显示引用实际值的定位符的宽度。所以只有知道所有空间值都是内联值时,才可以放心地使用该函数。因此,下面的查询根据空间数据类型的属性来计算数据的宽度。关于属性的信息可以从 DB2 编目视图 SYSCAT.DATATYPES 和 SYSCAT.ATTRIBUTES 获得。如果空间数据是使用结构类型实现的,那么在 SQL Reference 中关于CREATE TYPE 语句的解释中提到的判断结构类型值宽度的法则同样适用(请参阅 参考资料 一节,了解关于 CREATE TYPE 语句的信息)。具体地说,ST_Geometry 类型定义 16 个属性,它的子类型都没有添加自己的属性。除了三个属性外,所有属性都是所谓的 短属性。其中两个非短属性anno_text 和ext 没有被使用,第三个非短属性points 包含内部编码为 BLOB 的几何图形信息。除了实际的数据外,DB2 需要维护强制的 null 指示符(1 个字节)和长度信息(4 个字节)。因此,几何图形的大小可以通过公式 “32 + 16*10 + 5 + LENGTH(points) = 197 + LENGTH(points)” 得出。

清单 3. 几何图形的空间需求

-- maximum space requirement for spatial point data CREATE TABLE test ( p db2gse.ST_Point INLINE LENGTH 3800 )@ INSERT INTO test VALUES ( db2gse.ST_Point( 1234567890123456, 1234567890123456, 1234567890123456, 1234567890123456, 0) )@ SELECT LENGTH(p) FROM test@ 1 ----------- 245 1 record(s) selected. -- determining the size of all geometries in a table SELECT 197 + LENGTH(geometry..points) FROM spatial_data@ -- calculating #geometries that would be stored inline/lobified -- for a given inline length SELECT SUM(inline) AS inline, COUNT(*) - SUM(inline) AS lobified FROM ( SELECT CASE WHEN 197 + LENGTH(geometry..points) <= THEN 1 ELSE 0 END FROM spatial_data ) AS t(inline)@

性能比较

为了演示小的 inline length 与大的 inline length 的效果,我们首先将 shapefile 文件 europe/roads.shp 导入到一个 inline length 为 292 的表中。这是 DB2 允许的最小值。接着运行一个 SQL 脚本,该脚本确定有多少几何图形以内联方式存储,有多少几何图形必须以大对象化的方式存储。然后测量执行一个简单空间查询的时间,并显示在执行期间产生的语句快照的一个摘录,以揭示影响性能的最突出的因素。整个过程在 inline length 为 2000 的情况下再重复一遍,2000 这个值足以导致那个 shapefile 文件中的所有几何图形都以内联方式存储。下载 一节中包含了我们运行db2batch 时使用的脚本 test_inline_length.sql。

清单 4. 不同 inline length 设置的效果

$ time db2se import_shape testdb -fileName /home/stolze/europe/roads -srsName WGS84_SRS_1003 -tableName roads -createTableFlag 1 -spatialColumn shape -typeName ST_LineString -inlineLength 292 -idColumn id -commitScope 1500 GSE0000I The operation was completed successfully. real 3m15.604s user 0m0.050s sys 0m0.026s $ db2batch -d testdb -f test_inline_length.sql -i complete -s on --------------------------------------------- Statement number: 1 SELECT SUM(inline) AS inline_storage, COUNT(*) - SUM(inline) AS lobified_storage FROM ( SELECT CASE WHEN 197 + LENGTH(shape..points) <= ( SELECT inline_length FROM syscat.columns WHERE colname = 'SHAPE' AND tabname = 'ROADS' ) THEN 1 ELSE 0 END FROM roads ) AS t(inline) INLINE_STORAGE LOBIFIED_STORAGE -------------- ---------------- 89595 21384 --------------------------------------------- Statement number: 2 SELECT id FROM roads WHERE db2gse.ST_Intersects(shape, db2gse.ST_LineString( 'linestring(10 50, 20 40)', 1003)) = 1 Prepare Time is: 0.000 seconds Execute Time is: 0.854 seconds Fetch Time is: 0.000 seconds Elapsed Time is: 0.855 seconds Buffer pool data logical reads = 16818 Buffer pool index logical reads = 19731 Direct reads = 3088 Direct read requests = 1544 Direct read elapsed time (ms) = 18 --------------------------------------------- $ db2 "DROP TABLE roads" $ time 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. real 1m57.212s user 0m0.049s sys 0m0.027s $ db2batch -d testdb -f test_inline_length.sql -i complete -s on --------------------------------------------- Statement number: 1 SELECT SUM(inline) AS inline_storage, COUNT(*) - SUM(inline) AS lobified_storage FROM ( SELECT CASE WHEN 197 + LENGTH(shape..points) <= ( SELECT inline_length FROM syscat.columns WHERE colname = 'SHAPE' AND tabname = 'ROADS' ) THEN 1 ELSE 0 END FROM roads ) AS t(inline) INLINE_STORAGE LOBIFIED_STORAGE -------------- ---------------- 110979 0 --------------------------------------------- Statement number: 2 SELECT id FROM roads WHERE db2gse.ST_Intersects(shape, db2gse.ST_LineString( 'linestring(10 50, 20 40)', 1003)) = 1 Prepare Time is: 0.000 seconds Execute Time is: 0.792 seconds Fetch Time is: 0.000 seconds Elapsed Time is: 0.792 seconds Buffer pool data logical reads = 17337 Buffer pool index logical reads = 19731 Buffer pool index physical reads = 0 Direct reads = 2 Direct read requests = 1 Direct read elapsed time (ms) = 0 ---------------------------------------------


从结果中可以看出,对于重要操作,较大的 inline length 可以增加 40% 的速度,对样本数据的查询也快了 7%。这两种差异的底层原因是,当使用较小的 inline length 时,有超过 20000 个几何图形(大约 20% 的数据)以大对象化的方式存储。DB2 直接从磁盘读(写) LOB 数据。而在第二种场景中,大部分的直接读是不需要的,因为可以用存储在缓冲池中的内联数据来满足查询。注意,大对象化的数据所占的 20% 的比例实际上不算很坏。如果由于稍微复杂一点儿的几何图形导致更多的数据不能以内联方式存储,那么这里演示的差异还要大大增加。

阅读(682) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~