Sql 有效计算距离

Sql 有效计算距离,sql,sas,proc,proc-sql,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

我正试图找出每个地方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英里内所有地方的计数

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


我怎样才能更有效地处理这个问题

Gord在评论中提到了这一点,只需在查询中添加一个过滤器,您就可以避免重复计算和计算到self的距离

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; 
PROC-SQL;
创建表格距离\u表格\u 1作为
挑选
MASTER.PlaceID作为PlaceID
,Master.INTPTLAT为LAT1
,Master.INTPTLONG AS long 1
,Match.INTPTLAT为LAT2
,Match.INTPTLONG为LONG2
,测地仪(Master.INTPTLAT,Master.INTPTLONG,Match.INTPTLAT,Match.INTPTLONG,'M')作为距离
从主控台清洁主控台
交叉连接主表作为匹配
其中match.PlaceID
添加where条款:

where match.PlaceID < master.PlaceID
其中match.PlaceID
将返回449985000条记录((n^2-n)/2)。希望它足够小,可以处理


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

Gord在评论中提到了这一点,只需在查询中添加一个过滤器,您就可以省去重复计算和计算自我距离

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; 
PROC-SQL;
创建表格距离\u表格\u 1作为
挑选
MASTER.PlaceID作为PlaceID
,Master.INTPTLAT为LAT1
,Master.INTPTLONG AS long 1
,Match.INTPTLAT为LAT2
,Match.INTPTLONG为LONG2
,测地仪(Master.INTPTLAT,Master.INTPTLONG,Match.INTPTLAT,Match.INTPTLONG,'M')作为距离
从主控台清洁主控台
交叉连接主表作为匹配
其中match.PlaceID
添加where条款:

where match.PlaceID < master.PlaceID
其中match.PlaceID
将返回449985000条记录((n^2-n)/2)。希望它足够小,可以处理


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

当您加入一个表时,您需要尝试完成一些有助于提高性能的事情:

  • 使生成的数据集尽可能小
  • 尽可能容易地比较这两个条目
看到问题了吗?您根本没有减少数据集,而是执行了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
选择*
来自城市c1
加入城市c2
关于c1.ID
。。。这将使你得到一个可能的候选人小得多的名单。这并不是最终的答案——你会看到一些城市在另一个城市的北面25英里,西面25英里,总里程超过30英里。但是,您已经大大减少了需要执行的距离检查的总数,以及正在执行操作的数据集

之后,您应该在表上使用索引。我的猜测是,您需要一个同时包含Lat和Long列的索引,这样您只需要一个索引来执行操作


这应该有希望让你达到你需要去的地方-我猜这就是你需要的所有优化。但是如果你需要让事情变得更快,你可以细分数据。毕竟,该国西部地区与东部地区的距离不会超过30英里。(不过,你需要考虑到处于分界线边缘的城市。)

当你加入一个与自身对立的表格时,你需要尝试完成一些事情来帮助提高绩效:

  • 使生成的数据集尽可能小
  • 尽可能容易地比较这两个条目
看到问题了吗?您根本没有减少数据集,而是执行了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
选择*
来自城市c1
加入城市c2
关于c1.ID
。。。这将使你得到一个可能的候选人小得多的名单。这并不是最终的答案——你会看到一些城市在另一个城市的北面25英里,西面25英里,总里程超过30英里。但是,您已经大大减少了需要执行的距离检查的总数,以及正在执行操作的数据集

之后,您应该在表上使用索引。我的猜测是,您需要一个同时包含Lat和Long列的索引,这样您只需要一个索引来执行操作

这应该有希望让你达到你需要去的地方-我猜这就是你需要的所有优化。但是如果你需要让事情变得更快,你可以细分数据。毕竟,该国西部地区与东部地区的距离不会超过30英里。(不过,你需要考虑到你分水岭边缘的城市。)

减少这一对