在 SQL Server 2012 上使用带有空间索引的 STDistance 比使用 COS、SIN 和 ACOS 计算要慢,并给出椭圆形的结果

Posted

技术标签:

【中文标题】在 SQL Server 2012 上使用带有空间索引的 STDistance 比使用 COS、SIN 和 ACOS 计算要慢,并给出椭圆形的结果【英文标题】:Using STDistance with Spatial index on SQL Server 2012 is slower then using COS, SIN & ACOS Calculations and gives oval shaped results 【发布时间】:2015-08-25 13:30:21 【问题描述】:

我在 SQL Server 2012 数据库中有一个包含 3.000.000 条记录的表。这些记录代表地图上的一个点。所有这些记录都有 x、y 坐标和地理点作为字段(x、y、geo)。 我需要计算距离某个点 10.000 米范围内的所有点。

查询编号1 我用:

DECLARE @point geography
DECLARE @rad float

SET @point = geography::STGeomFromText('POINT(51.2207099068778  4.39961050577564)', 4326);
SET @rad = 10000

SELECT count(1) 
FROM t_mailbox WITH (INDEX(SIndx_t_mailbox_geo_MHHM_512))
WHERE 
@point.STDistance(geo) <= @rad

结果:找到 273.346 个点需要 4 秒。在地图上绘制这些点会在地图上形成椭圆形。 这肯定是错误的,因为并非所有点都包含在结果中。

查询编号2 我使用:

declare @radius int = 10000

DECLARE @x float = 51.2207099068778
DECLARE @y float = 4.39961050577564

SELECT count(1) 
FROM t_mailbox
WHERE 
ACOS(COS(RADIANS(90-@x))*COS(RADIANS(90-x)) +SIN(RADIANS(90-@x)) *SIN(RADIANS(90-x))*COS(RADIANS(@y-y)))*6371000 <= @radius

结果:找到 564.547 个点需要 2 秒。在地图上绘制这些点会形成一个完美的圆形。

问题:

    为什么使用 SPATIAL INDEX 和 STDistance 比使用 SIN、COS 和 ACOS 进行更复杂的查询要慢? 为什么会导致错误的椭圆形点集?

我做错了什么?

【问题讨论】:

第一个查询有SET @rad = 10000,但第二个查询有declare @radius int = 20000。这可能是您在第二个查询中获得更多行的原因吗? 抱歉,两个查询的半径都必须是 10.000 米。我改变了它的问题 如果两个查询中的半径均为 10000,我预计差异会更小。你在第二个查询中仍然得到这么多行(几乎是第一个的两倍)? This link works perfectly for me 【参考方案1】:

地理数据绘制在球体表面上。这意味着它看起来与几何(平面)数据不同。

想象一下拿一个地球仪,在上面画一个点。然后拿一个指南针并围绕该点画一个圆圈。现在剥去地球上的皮肤。请注意,它不会平躺,要使其平整,您必须将其拉伸。现在大多数人这样做的方式是拉伸顶部和底部(北极/南极)并将其拉伸到与赤道相同的长度。这会让你画的圆圈变成一个水平方向大于垂直方向的椭圆。

现在您使用的公式适用于平面半径内的点。这意味着无论您在哪个纬度,您都假设两条经线之间的距离是相同的(距离北极 5 英尺,经度 90 度和 91 度之间的距离远小于赤道处的距离)。

在墨卡托投影地图上,这个公式将生成一个完美的圆形地图,但在地球仪上,它不是。希望这是有道理的。

至于你的速度问题: A:苹果和橘子,你在做不同的计算。 B:在不知道如何设置索引的情况下,很难进行分析,但地理索引无论如何都非常糟糕,它在像国家这样的非常大的地理区域上效果更好。

【讨论】:

这是正确答案,我喜欢“剥离”类比@hcaelxxam!来自我的 +1。【参考方案2】:

虽然 hcaelxxam 完美地回答了“为什么”,但您可能离开STDistance() 会发现更好的性能。虽然并非总是如此,但我通常发现使用 STIntersects()STWithin() 来表示距离会更好 - 你如何做到这一点非常简单!

尝试将您的查询更改为以下内容。我会对结果感兴趣:

DECLARE @point geography;
DECLARE @rad float = 10000;

SET @point = geography::STGeomFromText('POINT(51.2207099068778  4.39961050577564)', 4326).STBuffer(@rad); -- We're creating the "oval" here

SELECT count(1) 
FROM t_mailbox WITH (INDEX(SIndx_t_mailbox_geo_MHHM_512))
WHERE 
@point.STIntersects(geo) = 1

您可能还想尝试使用和不使用索引提示。有时,强制它会生成一个低效的查询计划。

【讨论】:

以上是关于在 SQL Server 2012 上使用带有空间索引的 STDistance 比使用 COS、SIN 和 ACOS 计算要慢,并给出椭圆形的结果的主要内容,如果未能解决你的问题,请参考以下文章

处理 SQL Server 2012 表中的空间数据类型

如何在临时 sql server 上使用带有 Robot Framework 的数据库库

使用 sqlalchemy 和 pyodbc 连接到 SQL Server 2012

MS SQL Server 2012:网络访问配置不起作用

sql server 2008 使用过程中遇到虚拟池可用内存不足?请问这种问题怎么解决?

Win10 下卸载sql server 2012的问题