在 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

我在 SQL Server 2012 数据库中有一个 table,有 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

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

查询编号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

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

问题:

  1. 为什么使用 SPATIAL INDEX 和 STDistance 比使用 SIN、COS 和 ACOS 的更复杂查询慢?
  2. 为什么结果是一组错误的椭圆形点?

我做错了什么?

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

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

现在您使用的公式适用于平面上半径范围内的点。这意味着你假设两条经线之间的距离是相同的,无论你在什么纬度(距北极 5 英尺,90 度和 91 度经度之间的距离比赤道小得多)。

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

关于你的速度问题: A: apples to oranges,你是在做不同的计算。和 B:不知道你是如何建立索引的,很难分析,但地理索引无论如何都非常糟糕,它在像国家这样的非常大的地理区域上效果更好。

虽然 hcaelxxam 完美地回答了 "why",但您 可以 通过远离 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

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