自然界中的几何对象都是奇形怪状的,对这样的数据进行管理是一件很头疼的事情。因此,GIS的工程师们化繁为简,一种方法就是把几何对象的边界范围拿出来作为一个检索的依据(几何对象肯定在它内部),这是一个矩形的范围,再对它进行管理就方便多了。在Oracle Spatial中,基于R树的空间索引采用的就是这种方法(这也是推荐的索引算法),这个矩形叫MBR:Minimum Bounding Rectangle。
图 4 Oracle Spatial中几何对象的MBR
在Oracle Spatial中,一个空间表里所有的几何对象就是通过它们的MBR的R树索引进行管理的,从下面的图中很容易可以理解,MBR索引的根节点包括A、B两个较大的MBR,当一个查询可以很快速地找到A后,再查找其中的a或b这两个比较小的MBR,如果找到了a,那么再最终找到1或者2这两个最小的MBR。
图 5 R树索引的MBR示意图
对于上面我们创建过索引的测试表TEST_INDEX来说,他的MBR的索引相关信息存放在USER_SDO_INDEX_METADATA视图中:
SQL> select sdo_index_table,SDO_RTREE_HEIGHT,SDO_RTREE_NUM_NODES from user_sdo_index_metadata where sdo_index_name='IDX_TEST_INDEX_GEOM';
SDO_INDEX_TABLE SDO_RTREE_HEIGHT SDO_RTREE_NUM_NODES
----------------------------- ------------------------- ---------------------------------
MDRT_1350B$ 4 3336
如果我们打开一下MDRT_1350B$这张表,你可以看到里面存储着R树中每个节点的信息:
SQL> desc mdrt_1350B$
名称 是否为空? 类型
----------------------------------------------------------------- -------- --------------------------------------------
NODE_ID NUMBER
NODE_LEVEL NUMBER
INFO BLOB
SQL> select * from mdrt_1350B$ where node_level=3 and rownum<3;
NODE_ID NODE_LEVEL
---------- ----------
INFO
------------------------------------------------------------------------------------------------------------------------
3336 3
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000001F000000080D0000
0000000041414154554D414147414141426F6F41
3337 3
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000001F000000090D0000
0000000041414154554D414147414141426F5241
Oracle Spaital并不鼓励使用四叉树空间索引,除非某些特殊场景并且你确认采用四叉树索引会带来好处[1] 。Oracle提供了一个表格对比了R树空间索引和四叉树空间索引的一些特点。
R 树 |
四叉树 |
不能很好地近似几何对象(MBR对奇形怪状的几何对象的近似比较粗略) |
可以较好地近似几何对象 |
索引创建和调整比较简单 |
索引调整较复杂,而且索引的参数对性能影响较大 |
存储空间较小 |
存储空间较大 |
SDO_NN操作较快,同时还可以指定操作的SDO_BATCH_SIZE参数 |
相反 |
大批量更新数据时可能会降低空间表的访问效率 |
数据更新于访问效率无关 |
可以对4个维度进行索引 |
只能索引2个维度 |
对于地理坐标系的数据,并会使用到SDO_WITHIN_DISTANCE操作时,建议使用R树索引 |
相反 |
对于whole-Earth数据[2] 只能使用R树索引 |
相反 |
四叉树空间索引的原理像地图切片的原理,如图 6,可以想象,分级的级别越多,对几何对象的描述会更准确。
图 6 Oracle Spatial四叉树空间索引示意图
一般在Oracle Spatial创建四叉树空间索引采用固定切片范围的方式,这种方式根据当前的地图范围和SDO_LEVEL参数的设置,如果SDO_LEVEL为1,那就相当于整个图层一个切片;如果SDO_LEVEL为2,则整个图层等分为4块;依次类推。另外,在四叉树索引中,几何对象的每个Element都会被索引,如图 7。
图 7 四叉树空间索引中几何对象的Element
通过如下的方式可以创建一个固定切片大小、8级深度的四叉树空间索引:
SQL> create index idx_continent_geom on spatial.continent(geom) indextype is mdsys.spatial_index parameters('SDO_LEVEL=8');
索引已创建。
已用时间: 00: 05: 11.48
SQL> select sdo_index_type,sdo_index_table from user_sdo_index_metadata where sdo_index_name='IDX_CONTINENT_GEOM';
SDO_INDEX_TYPE
------------------------------------------------------------------------------------------------
SDO_INDEX_TABLE
------------------------------------------------------------------------------------------------
QTREE
MDQT_13537$
这里存放索引数据的表名字叫MDQT_13537$,可以查看这个表的结构和R树索引的表已经完全不同了:
SQL> desc MDQT_13537$
名称 是否为空? 类型
----------------------------------------------------------------- -------- --------------------------------------------
SDO_CODE RAW(16)
SDO_ROWID ROWID
SDO_STATUS VARCHAR2(1)
SQL> select * from MDQT_13537$ where rownum<10;
SDO_CODE SDO_ROWID SDO_STATUS
-------------------------------------- ------------------------------- ----------------
CBD9 AAATUWAAGAAABNGAAA B
CBDC AAATUWAAGAAABNGAAA B
CBDD AAATUWAAGAAABNGAAA I
CBDE AAATUWAAGAAABNGAAA B
CBDF AAATUWAAGAAABNGAAA B
CC00 AAATUWAAGAAABNGAAA I
CC01 AAATUWAAGAAABNGAAA I
CC02 AAATUWAAGAAABNGAAA I
CC03 AAATUWAAGAAABNGAAA I
其中SDO_STATUS的值如果是B表示几何对象和当前的切片边界相交;如果是I表示几何对象在当前切片之内。
[1] 《Oracle Spatial Quadtree Indexing》:The use of spatial quadtree indexes is discouraged. You are strongly encouraged to use R-tree indexing for spatial indexes, unless you need to continue using quadtree indexes for special situations.
[2] Oracle Spatial中包含一个whole-Earth几何模型,可以直接在地理坐标系的数据上根据地球表面曲率等参数进行真实长度、面积的计算,类似内置的投影算法