我在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秒钟。在地图上绘制这些点可以得到一个完美的圆形。
问题:
我做错了什么?
答案 0 :(得分:1)
地球数据绘制在球体表面上。这意味着它看起来与几何(平面)数据不同。
想象一下,拿一个地球仪,并在其上画一点。然后拿一个指南针围绕该点画一个圆圈。现在将皮肤剥离地球。请注意,它不是平坦的,要使它平坦,你必须伸展它。现在大多数人这样做的方式是伸展顶部和底部(北极/南极)并拉伸它直到它与赤道相同的长度。这使得你画圆形的椭圆形水平方向比垂直方向更大。
现在,您使用的公式是平面内半径范围内的点。这意味着您假设两条经度线之间的距离无论您的纬度是多少(距离北极5英尺,90度和91度经度之间的距离远小于赤道)。
在墨卡托投影地图上,此公式将制作一个完美圆形的地图,但在地球上,它不是。希望这是有道理的。
关于速度问题:A:苹果到橘子,你正在做不同的计算。和B:在不知道如何设置索引的情况下,很难进行分析,但地理索引非常糟糕,无论在国家这样的大型地理位置上它的效果都更好。
答案 1 :(得分:0)
虽然 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
您可能还希望尝试使用和不使用索引提示。有时,强制它可能会生成低效的查询计划。