空间索引应用

前篇:http://www.cnblogs.com/Gin-23333/p/4995199.html  _(:з」∠)_

空间索引,一个专门用来处理空间数据计算的索引,目前支持 STContains()、STDistance()、STEquals()、STIntersects()、STOverlaps()、STTouches() 和 STWithin()

然而通常我们平常使用的,通常就是 STDistance() 求两点之间的距离。

更加详细の资料,请戳:https://msdn.microsoft.com/zh-cn/library/bb895265(v=sql.120).aspx

先看下空间索引的创建语法,简单的必填项就是酱~

CREATE SPATIAL INDEX IndexName ON #Tmp(GeographyCoordinate)

WITH (BOUNDING_BOX=(XMIN=-180,YMIN=-90,XMAX=180,YMAX=90))

*最好要保证最大最小值要覆盖整个坐标系的值域,否则不能最有效使用索引

好,上个不太严谨的Sample

然后我们测试一下。创建了一个模拟酒店表 (数据量大概是45W左右)

Hotel,只有主键,其他没有任何东西,坐标存在 GeographyCoordinate 的栏位里面

Tmp_Hotel1 ,结构和Hotel完全一致,并在GeographyCoordinate 里面创建了一个空间索引。

DECLARE @DT DATETIME=GETDATE()
DECLARE @GEO GEOMETRY=GEOMETRY::STGeomFromText(‘POINT(39.8666 20.017)‘,0)

SELECT DATEDIFF(ms,@DT,GETDATE())
SELECT *
    FROM Hotel
        WHERE GeographyCoordinate.STDistance(@GEO) < 0.43
SELECT DATEDIFF(ms,@DT,GETDATE())
SELECT *
    FROM Tmp_Hotel1
        WHERE GeographyCoordinate.STDistance(@GEO) < 0.43      SELECT DATEDIFF(ms,@DT,GETDATE())

结果如下 ,可见第一句执行了1320ms ,第二句仅仅执行了 50ms,这是一个坐标在45W数据里面的大概分析情况

然后我们把比对的数据扩大10条,比如说我要找这10个酒店5公里之内的其他酒店。首先我会建个临时表存放那10间酒店的位置。

--随机取10条,避免被读取顺序误导
SELECT TOP 10 ID,
              GeographyCoordinate
        INTO #Tmp
    FROM dbo.Hotel
        WHERE ORDER BY NEWID()

顺手开个统计看看

SET STATISTICS IO ON

--不使用索引直接关联
SELECT a.*,b.ID
    FROM dbo.Hotel a
        INNER JOIN #Tmp b ON a.GeographyCoordinate.STDistance(b.GeographyCoordinate) < 0.43  

--使用索引关联
SELECT a.*,b.ID
    FROM dbo.Tmp_Hotel1 a
        INNER JOIN #Tmp b ON a.GeographyCoordinate.STDistance(b.GeographyCoordinate) < 0.43        

结果 28s,还有8次的Hotel物理扫描 ╮(╯_╰)╭

表 ‘#Tmp‘。扫描计数 1,逻辑读取 9 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Hotel‘。扫描计数 8,逻辑读取 241960 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

第二位空间索引选手的表现呢,执行时间18s。看起来比没有索引好不了多少

表 ‘Tmp_Hotel1‘。扫描计数 0,逻辑读取 1332493 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Workfile‘。扫描计数 48,逻辑读取 1384 次,物理读取 96 次,预读 1440 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘extended_index_907150277_384000‘。扫描计数 5413,逻辑读取 18390 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘#Tmp‘。扫描计数 1,逻辑读取 9 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

然而,根据资料,欲用空间索引,必先在Where 和 OrderBy 使用效果更佳。加上Order By 试下

SELECT a.*,b.ID
    FROM dbo.Tmp_Hotel1 a
        INNER JOIN #Tmp b ON a.GeographyCoordinate.STDistance(b.GeographyCoordinate) < 0.43
        ORDER BY a.GeographyCoordinate.STDistance(b.GeographyCoordinate)

执行时间6S,比没有OrderBy 选手好多了~

表 ‘#Tmp‘。扫描计数 1,逻辑读取 9 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Tmp_Hotel1‘。扫描计数 0,逻辑读取 1332549 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Workfile‘。扫描计数 48,逻辑读取 1440 次,物理读取 96 次,预读 1440 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘extended_index_907150277_384000‘。扫描计数 5413,逻辑读取 18525 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

看IO其实两边差不多,为什么时间差辣么远?我看了一下才发现,加上了OrderBy 之后,执行计划会使用并行,所以速度刷一下上去了

--尝试一下看看帮#Tmp加个空间索引会不会有更大提升
ALTER TABLE #Tmp ADD CONSTRAINT PK_Tmp PRIMARY KEY (ID)
CREATE SPATIAL INDEX #IX_Tmp ON #Tmp(GeographyCoordinate)
    WITH (BOUNDING_BOX=(XMIN=-180,YMIN=-90,XMAX=180,YMAX=90))

再执行一下第二句,执行时间也是差不多,应该是临时表数据量太少,没有走到索引,╮(╯_╰)╭。

表 ‘#Tmp‘。扫描计数 1,逻辑读取 3 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Tmp_Hotel1‘。扫描计数 0,逻辑读取 1332553 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Workfile‘。扫描计数 48,逻辑读取 1376 次,物理读取 96 次,预读 1440 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘extended_index_907150277_384000‘。扫描计数 5413,逻辑读取 18546 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 ‘Worktable‘。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

其实到这里,我觉得有个定性的认识就差不多了。

总结:要使用空间索引

1、主要对付查询 STDistance  函数等问题。

2、建索引的时候边界范围要禁可能包含出现的值域

3、在Where条件和 OrderBy 都要使用 STDistance 函数

4、特别注意Null 值会影响空间索引的性能

写在最后:

其实我也想过一下其他替代STDistance建空间索引的方式。

1、建一个对照表,预先做个笛卡尔积,这样就可以不用调度函数  (想到此方法先给自己2个耳光,维护成本太高了)

2、可以把XY值抽取出来,用个游标来做数值计算,不使用 STDistance 进行计算。这样我测试过性能还算可以。(但是逼格不够高,而且看起来有点蠢╮(╯_╰)╭)

3、一般来说可以用Top 或者其他条件加强筛选,减少待计算的数据量,也有助于提高性能。

时间: 2024-09-29 10:33:18

空间索引应用的相关文章

Mysql空间数据,空间索引,Spatial Data,Spatial Index

前文: 这两天因为项目原因看了一下MySQL的空间索引,发现网上的资料不多,查了一下官方文档,为了强化记忆做了一个简单的翻译.基本上理解了mysql空间索引的要点.谨以此纪. Extensions for Spatial Data Open Geospatial Consortium (OGC) 是一个由超过两百五十个公司,机构,大学组成的致力于发展管理空间数据的解决方案的组织. OGC 发布了OpenGIS® Implementation Standard for Geographic inf

MongoDB 学习笔记之 地理空间索引入门

地理空间索引: 地理空间索引,可用于处理基于地理位置的查询. Point:用于指定所在的具体位置,我们以restaurants为例: db.restaurants.insert({name: "Citi", loc: {type: "Point", coordinates: [52.37, 5.21]}}) db.restaurants.insert({name: "SAP", loc: {type: "Point", coo

mysql对GIS空间数据的支持,包括创建空间索引

CREATE TABLE tb_geo( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(128) NOT NULL, pnt POINT NOT NULL, SPATIAL INDEX `spatIdx` (`pnt`) <!-- 1.创建表时创建空间索引 --> )ENGINE=MYISAM DEFAULT CHARSET=utf8; <!-- 数据库表引擎设置为 MYISAM--> <!-- 2.已经存在的表上创建索引 -

Python访问PostGIS(建表、空间索引、分区表)

#encoding: utf-8 __author__ = 'Administrator' import psycopg2 import ppygis import datetime import string import sys import logging import GeowayLogger reload(sys) #中文错误 sys.setdefaultencoding( "utf-8" ) vLog = GeowayLogger.GeowayLogger("c:

四叉树空间索引原理及其实现

今天依然在放假中,在此将以前在学校写的四叉树的东西拿出来和大家分享. 四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构.它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割.四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是GIS中常用的空间索引之一.常规四叉树的结构如图所示,地理空间对象都存储在叶子节点上,中间节点以及根节点不存储地理空间对象. 四叉树示意图 四叉树对于区域查询

mongoDb地理空间索引和查询

一.MongoDb介绍(http://docs.mongoing.com/manual/applications/geospatial-indexes.html) MongoDB提供了一系列的索引和查询机制来处理地理空间信息.这一节会介绍MongoDB的地理索引特性.您可以阅读 地理索引教程 来了解关于MongoDB中地理查询的完整示例. 表面 在您存储地理数据和编写查询条件前,首先,您必须选择表面类型,这将被用在计算中.您所选择的类型将会影响您的数据如何被存储,建立的索引的类型,以及您的查询的

空间索引 - GeoHash算法及其实现优化

h1,h2,h3,h4,h5,h6,p,blockquote { margin: 0; padding: 0 } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; font-size: 13px; line-height: 18px; color: #737373; background-color: white; margin: 10px

空间索引 - 各数据库空间索引使用报告

h1,h2,h3,h4,h5,h6,p,blockquote { margin: 0; padding: 0 } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; font-size: 13px; line-height: 18px; color: #737373; background-color: white; margin: 10px

SQL Server 2008空间数据应用系列二:空间索引(Spatial Index)基础

原文:SQL Server 2008空间数据应用系列二:空间索引(Spatial Index)基础 在前一篇博文中我们学习到了一些关于地理信息的基础知识,也学习了空间参照系统,既地球椭球体.基准.本初子午线.计量单位.投影等相关理论知识,我们可以使用这些空间参照系统组件来定义一系列应用于地球空间上的几何图像来表示地理空间中的特定功能,表示着地球上一个一个特定的位置点. 本篇主要介绍地理空间索引的概念以及微软SQL Server 2008 R2中的空间索引的应用. 一.空间索引 空间索引是指依据空