SQL Server 地理

Posted

技术标签:

【中文标题】SQL Server 地理【英文标题】:SQL Server Geography 【发布时间】:2016-08-02 11:04:31 【问题描述】:

是否有任何可能的方法来改进以下查询:

DECLARE @radiusInMeters FLOAT = 400;
DECLARE @dgeog geography = geography::Point(given_latitude, given_longitude, 4326).STBuffer(@radiusInMeters);

select [fdx].latitude, [fdx].longitude
from [dbo].[fdx]
where @dgeog.STIntersects(geography::STGeomFromText('POINT(' + convert(varchar(20), [fdx].longitude) + ' ' + convert(varchar(20), [fdx].latitude) + ')', 4326)
                         ) = 1

【问题讨论】:

以什么方式提高? 您的查询不使用任何空间索引,并且您的表没有几何列。所以查询运行时间太长了。 我的问题有点误导。对此感到抱歉。我的表确实有一个地理列和一个空间索引。但是空间索引没有出现在执行计划中。也许它与地理字段的创建方式有关 【参考方案1】:

kcung 和 Hasan BINBOGA 是正确的,你需要一个空间索引。

查看您的查询: @dgeog.STIntersects(xxxx) = 1 这要求 [xxxx] 是地理数据类型。为了使 [xxxx] 成为地理数据类型,必须将 STGeomFromText 函数应用于该行。由于这是 WHERE 子句的唯一部分,因此该函数必须应用于所有行。

如果表 fdx 特别大,这意味着必须一遍又一遍地应用 CLR 函数。这不是(在 SQL-Server 术语中)一个快速的过程。

如果可以的话,试试这个:

ALTER dbo.fdx ADD Point AS (GEOGRAPHY::Point(Latitude, Longitude, 4326)) PERSISTED
GO
CREATE SPATIAL INDEX SIndex_FDX ON dbo.fdx (Point) 
USING GEOGRAPHY_GRID
WITH (
  GRIDS = (LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
  CELLS_PER_OBJECT = 1
)
GO
DECLARE @Latitude DECIMAL(15,10) = 0
DECLARE @Longitude DECIMAL(15,10) = 0
DECLARE @Radius FLOAT = 400
DECLARE @g GEOGRAPHY = GEOGRAPHY::Point(@Latitude, @Longitude, 4326).STBuffer(@Radius)
SELECT * FROM dbo.fdx WHERE Point.STIntersects(@g) = 1

注意:您应该先将纬度/经度对转换为小数,然后再使用它们来计算地理列。当您使用浮点数作为输入时,存在从浮点数到十进制到字符串的隐式转换,这会将您的坐标修剪到小数点后 4 位。如果您先显式转换,那将不是问题。

另外,如果您在 dbo.fdx 中有任何空的纬度/经度值,您需要在 WHERE 子句中过滤它们,因为空值会导致您的空间索引无法正常工作。

【讨论】:

正如我在上面给Hasan BINBOGA的回复中提到的,空间索引出现在执行计划中。但是,我使用您的语句重新创建了该列,现在执行计划不同了。 @ancdev 空间索引与空间列相关联。在您的查询中,您永远不会引用空间列,而是使用 GEOGRAPHY::STPointFromText() 来计算空间值,并且由于显而易见的原因,计算值不能被空间索引引用。【参考方案2】:

您可以创建空间索引: https://msdn.microsoft.com/en-us/library/bb934196.aspx

【讨论】:

如果是这种情况,那么您应该使用查询提示。在“from”子句中的表名之后添加:with(index())。您会惊讶地发现,在进行空间查询时,我需要提示 sql server 多少次使用正确的索引。

以上是关于SQL Server 地理的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 地理

SQL Server - 地理

Microsoft SQL Server 上的地理数据

SQL Server 2008 - 从记录中获取地理位置

SQL Server 地理测试点是不是在范围内 - STWithin() 做啥?

SQL Server:检查两个地理/几何的边界是不是相互交汇