有效地计算距离

时间:2018-04-16 17:36:34

标签: sql sas proc proc-sql

我试图找到每个地方30英里范围内的地方数量。例如,对于伊利诺伊州斯普林菲尔德,半径30英里的城镇有多少?

对于每个地方,我都有名字,纬度和经度,n = 30k。

如果数据集较小,这个问题会相对简单:

PROC SQL; 
    CREATE TABLE Distance_Table_1 AS 
        SELECT 
             MASTER.PlaceID AS PlaceID 
            ,Master.INTPTLAT AS LAT1
            ,Master.INTPTLONG AS LONG1
            ,Match.INTPTLAT AS LAT2
            ,Match.INTPTLONG AS LONG2
            ,GEODIST(Master.INTPTLAT, Master.INTPTLONG, Match.INTPTLAT,Match.INTPTLONG,'M') AS DISTANCE
        FROM MASTER_TABLE_CLEANED_ MASTER
        CROSS JOIN MASTER_TABLE_CLEANED_ AS MATCH
        ; 
QUIT; 
然后,我会为每个地方创建30英里范围内所有地方的计数。

问题是,这会产生一个我无法处理的无法处理的大表(900M行)。

我如何更有效地处理这个问题?

3 个答案:

答案 0 :(得分:1)

戈德在评论中提到了这一点,只需在查询中添加一个过滤器,就可以减少重复计算和自我距离的计算。

PROC SQL; 
    CREATE TABLE Distance_Table_1 AS 
        SELECT 
             MASTER.PlaceID AS PlaceID 
            ,Master.INTPTLAT AS LAT1
            ,Master.INTPTLONG AS LONG1
            ,Match.INTPTLAT AS LAT2
            ,Match.INTPTLONG AS LONG2
            ,GEODIST(Master.INTPTLAT, Master.INTPTLONG, Match.INTPTLAT,Match.INTPTLONG,'M') AS DISTANCE
        FROM MASTER_TABLE_CLEANED_ MASTER
        CROSS JOIN MASTER_TABLE_CLEANED_ AS MATCH
        where match.PlaceID < master.PlaceID
        ; 
QUIT; 

添加where子句:

where match.PlaceID < master.PlaceID

这将返回449,985,000条记录((n ^ 2-n)/ 2)。希望这个小到可以处理。

(这需要1:05在我的笔记本电脑上有30k记录的测试台上运行)

答案 1 :(得分:1)

如果你自己加入一张桌子,你想尝试完成一些事情来帮助提高绩效:

  • 使结果数据集尽可能小
  • 尽可能简单地比较两个条目

看到问题?您根本没有减少数据集,并且您正在执行30k x 30k次的复杂距离计算。我们不会尽可能快地消除尽可能多的可能记录,而是继续前进,并在前面强制执行所有事情。

立即开始,提高性能的一个简单方法就是做一些事情:

select *
from cities c1
JOIN cities c2
on c1.ID < c2.ID
and c2.Lat between c1.Lat - 30 miles and c1.Lat + 30 miles
and c2.Long between c1.Long - 30 miles and c1.Long + 30 miles

...这将为您提供 更小的可能候选人列表。这不是最终的答案 - 你将拥有距离北方25英里,距离另一座城市以西25英里的城市,这超过了30英里。但是,您极大地减少了您需要进行的距离检查的总数,以及您正在进行操作的数据集。

之后,你应该玩桌上的索引。我的猜测是你想要一个同时包含Lat和Long列的索引,这样你只需要一个索引来执行操作。

这应该有希望让你到达你需要去的地方 - 我的猜测是这是你需要的所有优化。但是如果你需要更快地制作东西,你可以细分数据。毕竟,该国西部地区的任何东西都不会在东部30英里范围内。 (不过,你需要考虑分裂边缘的城市。)

答案 2 :(得分:1)

减少对选择空间。

使用DomPazz PlaceId限制要评估的对的集合,并使用格子方法要求每个纬度和长值具有30英里的近似近似值。

成对选择标准是

where
  fromCity.placeId < toCity.placeId
  and abs(fromCity.lat - toCity.lat) < &precomputed_Max30mileLatRange
  and abd(fromCity.lont - toCity.long) < &precomputed_Max30mileLongRange

使用http://longitudestore.com/how-big-is-one-gps-degree.html上的信息:

  • 纬度标称名义上是线性的并且是纬度的“1度”。是~69英里
  • 纵向尺度变化,需要更长的时间。离你最近的北极或南极30英里。在北纬80度,1度经度大约12英里

因此,假设您的地图数据没有纬度超过80的地方,以下选择标准将大大减少需要计算地理距离的配对。

where
  fromCity.placeId < toCity.placeId
  and abs(fromCity.lat - toCity.lat) < 0.5 /* ~35 miles */
  and abs(fromCity.lont - toCity.long) < 2.5 /* anywhere from ~36 miles (at 80 lat to ~175mi at equator */

这一切都假设了一个球形的地球信仰。