一些补充测试结果:
为了测试Oracle Spatial和ArcSDE在相对真实的环境中几何对象存储空间的大小,测试分别使用了2个包含约1亿个要素的线数据和面数据进行。其中线数据只包含几何信息,面数据还包含一些属性信息。大部分线数据只包含2个节点,而面数据一般都是几十个节点以上
对这2个数据分别进行了存储空间的比较:
数据 |
存储类型 |
空间数据表存储大小(G) |
线数据 |
ST_GEOMETRY |
14.72 |
SDO_ GEOMETRY |
16.51 |
|
面数据 |
ST_ GEOMETRY |
49.93 |
SDO_ GEOMETRY |
87.87 |
可见随着几何对象节点数的增加,SDO_Geometry存储耗费的空间要多不少。
对于空间数据库进行空间查询的操作一般都有两个阶段,对于Oracle Spatial而言,一个空间查询分为2个步骤,一个称为主过滤(Primary Filter),另外一个称为次过滤(Secondary Filter)。主过滤通过矩形的MBR相交从海量的数据中首先过滤出可能符合空间查询的一小部分数据,然后再用次过滤中具体的空间关系算法来判断这个小的结果集中到底哪些是满足空间关系的。如图 12,在主过滤的过程中,空间索引会被使用到。
图 12 Oracle Spatial中空间查询的处理流程
对于ArcSDE来说,原理上也是类似,ArcSDE中有一个函数叫ST_ENVINTERSECTS,这就是通过四角坐标来从海量数据中过滤一个矩形范围内的一小部分数据。对于其它一般的空间操作,比如ST_WITHIN等,只要你的数据建立了空间索引,这个操作也会先通过空间索引找到一个小数据集(相当于ST_ENVINTERSECTS操作,或者说Oracle Spatial中的主过滤),然后再通过具体的“Within”的空间关系算法再查得准确的结果(相当于Oracle Spatial中的次过滤)。当然,如果数据没有空间索引,那么上面的操作就没有空间索引可用,不过ArcSDE也能查到结果,这比Oracle Spatial不建空间索引就不能作空间查询要好一些。
因此,从上一小节可以知道,空间索引的效率可以通过Oracle Spatial中的“主过滤”和ArcSDE的ST_ENVINTERSECTS的比较得到一个参考的结果。
以下是对上面使用过的约1亿条数据的线数据和面数据分别进行SQL语句查询的性能。测试代码如下:
public class PerformanceTest {
public static void main(String[] args) {
PerformanceTest test = new PerformanceTest();
test.execute();
}
private static final String url = "jdbc:oracle:thin:@192.168.200.224:1521:test";
private static final String user = "sde";
private static final String password = "sde";
public void execute() {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, user, password);
conn.setAutoCommit(false);
String sql = "select shape from sdo_test.streets where sdo_filter(shape,SDO_GEOMETRY(2003,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(-72.527,41.869,-72.493,41.869,-72.493,41.891,-72.527,41.891,-72.527,41.869)))='TRUE'";
long start = System.currentTimeMillis();
stmt = conn.prepareStatement(sql);
stmt.setFetchSize(1000);
int count = 0;
rs = stmt.executeQuery();
while (rs.next()) {
Object shape = rs.getObject(1);//读取几何对象值
count ++;
}
long end = System.currentTimeMillis();
System.out.println("查询结果:" + count);
System.out.println("查询时间:" + (end - start) + "ms");
} catch (Exception ex) {
ex.printStackTrace();
} finally{
try {
rs.close();
} catch (SQLException e) {
}
try {
stmt.close();
} catch (SQLException e) {
}
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
线数据测试结果,耗时单位为秒,每种类型分别对应前后两个结果分别代表在数据库中没有数据块缓存和缓存后的结果:
查询范围(真实结果数) |
ST_GEOMETRY |
SDO_ GEOMETRY |
||
范围约10个要素(8) |
0.357 0.156 |
0.218 0.203 |
||
范围约100个要素(114) |
0.734 0.203 |
0.811 0.203 |
||
范围约1000个要素(1341) |
0.920 0.250 |
0.951 0.234 |
||
范围约10000个要素(10414) |
2.386 0.562 |
3.104 0.400 |
面数据测试结果,耗时单位为秒,每种类型分别对应前后两个结果分别代表在数据库中没有数据块缓存和缓存后的结果:
查询范围(真实结果数) |
ST_ GEOMETRY |
SDO_ GEOMETRY |
||
范围约10个要素(16) |
0.530 0.160 |
0.780 0.203 |
||
范围约100个要素(133) |
2.636 0.343 |
1.841 0.220 |
||
范围约1000个要素(1104) |
8.034 0.500 |
8.517 0.300 |
||
范围约10000个要素(10494) |
29.952 1.310 |
43.010 0.950 |