SDE空间索引的内部运行机制2

2.2.1各种矢量数据存储类型的空间索引的实现方式

ArcSDE从开始到现在主要支持以下几种存储类型:

存储类型

数据库

SDELOB

Oracle,SQLServer,DB2

ST_GEOMETRY

Oracle,DB2,PostgresQL,Informix

SDO_GEOMETRY

Oracle

 

2.2.1.1 SDELOB

SDELOB是ArcSDE最先支持的也是最老的一种存储方式,这种存储方式类似于SHP文件的存储方式,它将属性数据和空间数据分别存储在两张表中,用ArcGIS的专业术语这两张表分别称作Business表和F表,其中Business表中存储属性数据,其简称B表,F表存储的是空间数据,至于数据库设计人员为什么将空间数据存储在以F打头的表中就不得而知了,如果是我设计,我可能把表名设计成以DATA打头。下图为抓取的B表和F表的表结构:

B表:

SQL> desc cities_1
 Name                                      Null     Type
 ----------------------------------------- -------- ---------------------------
 OBJECTID                                  NOT NULL NUMBER(38)
 CITY_NAME                                          NVARCHAR2(30)  
 GMI_ADMIN                                          NVARCHAR2(7)  
 ADMIN_NAME                                         NVARCHAR2(42)
 FIPS_CNTRY                                         NVARCHAR2(2)
 CNTRY_NAME                                         NVARCHAR2(30)
 STATUS                                             NVARCHAR2(50) 
 POP_RANK                                           NUMBER(5)
 POP_CLASS                                          NVARCHAR2(22) 
 PORT_ID                                            NUMBER(5) 
 LABEL_FLAG                                         NUMBER(5)
 SHAPE                                              NUMBER(38)

F表:

SQL> desc f1464
 Name                                      Null     Type
 ----------------------------------------- -------- --------------------------- 
 FID                                       NOT NULL NUMBER(38) 
 NUMOFPTS                                  NOT NULL NUMBER(38)  
 ENTITY                                    NOT NULL NUMBER(38)
 EMINX                                     NOT NULL FLOAT(64) 
 EMINY                                     NOT NULL FLOAT(64) 
 EMAXX                                     NOT NULL FLOAT(64) 
 EMAXY                                     NOT NULL FLOAT(64)  
 EMINZ                                              FLOAT(64) 
 EMAXZ                                              FLOAT(64) 
 MIN_MEASURE                                        FLOAT(64) 
 MAX_MEASURE                                        FLOAT(64) 
 AREA                                      NOT NULL FLOAT(64)
  
 LEN                                       NOT NULL FLOAT(64)  
 POINTS                                             BLOB

 

两个表是通过B表的SHAPE的字段和F表的FID字段关联起来,在此也引出一个常见的问题,有很多的人发出以下的疑问:

B表的SHAPE字段的类型是NUMBER,这个数据怎么来存储空间数据呢?

从上面的介绍中可以看出来,B表的SHAPE字段并没有存储空间数据,而只是指向空间数据表的一个索引,实际的数据是存储在F表的POINTS字段中,该字段的类型是BLOB。

对于SDELOB这种存储方式也是有空间索引,只是这个空间索引并不是在数据库层次上实现的,而是在应用层次上实现的。之所以这么说,是因为,在对使用SDELOB方式存储的两张表上查不到任何的空间索引,如下图:

B表上的索引:

SQL> select index_name,index_type from user_indexes where table_name='CITIES_1';
INDEX_NAME                     INDEX_TYPE 
------------------------------ -------------------------- 
A1464_IX1                      NORMAL  
R2067_SDE_ROWID_UK             NORMAL

两个索引都是Btree索引

F表的索引:

SQL> select index_name,index_type from user_indexes where table_name='F1464';
INDEX_NAME                     INDEX_TYPE
------------------------------ ---------------------------
SYS_IL0000092600C00014$$       LOB
F1464_UK1                      NORMAL

F表存在一个LOB索引和一个B-TREE索引, LOB索引从名称上能看出来是Oracle内部对BLOB字段所创建的自己维护的索引,并不是用户自己创建的,不是空间索引。

从上面的图例中可以看出来,在数据库的层面上并没有空间索引。

可能很多人并不理解在应用层面上实现的空间索引,下面来详细的解析这个问题,

先说一下索引信息的存储信息:

相信很多人都听说在ArcSDE中存在着S表,S实际上是Sptail Index Table单词的第一个字母,实际上这张表中存储的就是索引信息,以下为该表的数据结构:

SQL> desc s244_idx$
 Name                                      Null    Type
   3:  

 ----------------------------------------- -------- ----------------------------
 GX                                        NOT NULL NUMBER(38)
 
 GY                                        NOT NULL NUMBER(38)
 MINX                                      NOT NULL NUMBER(38)
 MINY                                      NOT NULL NUMBER(38)
 MAXX                                      NOT NULL NUMBER(38)
 MAXY                                      NOT NULL NUMBER(38)
 SP_ID                                     NOT NULL ROWID

红色部分就是ROWID,我在索引的基本原理提到过每个索引都会记录表记录的ROWID,在此得到了验证。

另外这张表也并不是Oracle的heap表,而是一个索引表,也就是这张表本身就是按照索引的顺序存储的,该表的具体定义可以见下图:

SQL> select dbms_metadata.get_ddl('TABLE','S244_IDX$','SDE') from dual;
DBMS_METADATA.GET_DDL('TABLE','S244_IDX$','SDE')
------------------------------------------------------------------------------
  CREATE TABLE "SDE"."S244_IDX$"(   
	      "GX" NUMBER(*,0),
              "GY" NUMBER(*,0),
              "MINX" NUMBER(*,0),
        "MINY" NUMBER(*,0),
        "MAXX" NUMBER(*,0),
        "MAXY" NUMBER(*,0),
        "SP_ID" ROWID,
         CONSTRAINT "S244$_IX1" PRIMARY
         KEY ("GX", "GY", "MAXX", "MAXY", "MINX", "MINY"),'S244_IDX$','SDE') ) ORGANIZATION INDEX
         NOCOMPRESS PCTFREE 0 INITRANS 4 MAXTRANS 255 LOGGIN)
  STORAGE(INITIAL 65536 NEXT
 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT

)
  TABLESPACE "SDE"  
 PCTTHRESHOLD 5
  MONITORING

再解析一下应用层次上实现的意思:

在使用ArcGIS的前端软件,如Desktop, ArcGIS Server的时候,进行地图浏览的时候,尤其是在大比例尺下浏览的时候, 前端软件所提交的SQL语句是S表和F表联合查询的语句,相当于先从S表中过滤出满足条件的ROWID,然后再根据ROWID到F表中快速查到相关的记录,因此这种空间索引的实现方式是在ArcGIS的前端应用软件中实现的。

以下所摘取的是使用ArcMap浏览数据的时候所抓取的Oracle后台所执行的SQL语句。

/opt/oracle/admin/test/udump/test_ora_15720.trc
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORACLE_HOME = /opt/oracle
System name:    Linux
Node name:    lstest
Release:    2.6.18-194.el5
Version:    #1 SMP Tue Mar 16 21:52:39 EDT 2010
Machine:    x86_64
Instance name: test
Redo thread mounted by this

 instance: 1
Oracle process number: 15
 
Unix process pid: 15720, image: oracle@lstest  

*** 2010-12-14 10:25:56.311  
*** ACTION NAME:() 2010-12-14 10:25:56.310  
*** MODULE NAME:(ArcCatalog.exe) 2010-12-14 10:25:56.310
*** SERVICE NAME:(SYS$USERS) 2010-12-14 10:25:56.310
*** SESSION ID:(136.314) 2010-12-14 10:25:56.310 
BINDS #25:
=====================
PARSING IN CURSOR #25 len=69 dep=0 uid=68 oct=3 lid=68 tim=1262005426085287 hv=2558560494 ad='8ca78d78'
SELECT table_name, time_last_modified FROM   SDE.sde_tables_modified
END OF STMT

EXEC #25:c=0,e=546,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1262005426085278
WAIT #25: nam='SQL*Net message to client'

 ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=92612 tim=1262005426085433
FETCH #25:c=0,e=117,p=0,cr=1,cu=0,mis=0,r=7,dep=0,og=1,tim=1262005426085510  
=====================
  29:  

PARSING IN CURSOR #45 len=443 dep=0 uid=68

 oct=3 lid=68 tim=1262005426089015 hv=2026582214 ad='83d2c968' 
SELECT /*+ INDEX(SHAPE F1464_UK1) */

 S_.eminx,S_.eminy,S_.emaxx,S_.emaxy ,SHAPE.fid,SHAPE.numofpts,SHAPE.entity,SHAPE.points,SHAPE.rowid  FROM (SELECT  /*+ INDEX(SP_ S1464_IX1) */

 DISTINCT

 sp_fid, eminx, eminy, emaxx, emaxy FROM SDE.S1464 SP_  WHERE SP_.gx >= :1 AND SP_.gx <= :2 AND SP_.gy >= :3 AND  

 SP_.gy <= :4 AND SP_.eminx <= :5 AND SP_.eminy <= :6 AND SP_.emaxx >= :7 AND SP_.emaxy >= :8) S_, SDE.F1464  

SHAPE  WHERE S_.sp_fid = SHAPE.fid
END OF STMT
EXEC #45:c=1000,e=822,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1262005426089006
WAIT #45: nam='SQL*Net message to client'

 ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=92612 tim=1262005426095016 
WAIT #45: nam='SQL*Net more data to client'

 ela= 39 driver id=1413697536 #bytes=2004 p3=0 obj#=92612 tim=1262005426095401 
WAIT #45: nam='SQL*Net more data to client'

 ela= 23 driver id=1413697536 #bytes=2000 p3=0 obj#=92612 tim=1262005426096039
FETCH #45:c=10998,e=10823,p=0,cr=50,cu=0,mis=0,r=57,dep=0,og=1,tim=1262005426099931

红色部分为前端软件所提交的SQL,第二个SQL即为S和F表联合查询的语句。同时请注意绿色部分的内容,dep=0 代表该SQL是应用软件所提交的SQL,并不是oracle自己内部所执行的SQL,uid=68代表执行该SQL语句的用户ID为SDE,见下面的数据:

SQL> select user_id from dba_users where username='SDE';

USER_ID
---------
68

至于如何抓取Oracle后台的日志,以及日志中的各项内容都代表什么意思,可以查看以下的链接:

http://blog.csdn.net/liufeng1980423/archive/2010/12/13/6072515.aspx

http://blog.csdn.net/liufeng1980423/archive/2010/12/14/6074521.aspx

转载自:https://blog.csdn.net/liufeng1980423/article/details/6082086

You may also like...