地理定位自我加入太慢

时间:2017-09-23 23:52:40

标签: sql geolocation sas self-join

我试图通过一个巨大的表(1m +记录)获取每条记录50英里内的所有记录的数量,使用自联接,如下所示:

{{1}}

这次跑了6个小时,上次检查时仍在运行。 有没有办法更有效地做到这一点?

更新:我的意图是从表latlon中确定的每个记录中获取半径50英里的新纽约人数,其中包含名称,位置和纬度/经度,其中lat / lon可以在任何地方在世界上,但位置将是一个人的家乡。我必须为近十几个城镇做这件事。看起来这是最好的。我可能不得不为这个编写一个C代码。

2 个答案:

答案 0 :(得分:2)

您正在使用的geodist()函数无法利用任何索引。所以,你有一个最好是O(n ** 2)的算法。那会很慢。

但是,您可以利用球形几何的简单事实来访问可索引查询。纬度(南北)相当于六十海里,69法定英里或111.111公里。英国对海里的定义最初等于一分钟。最初的拿破仑流量计被定义为从赤道到极点一万分之一的一部分,也被定义为90度。

(这些定义取决于地球是球形的假设。事实并非如此。如果你是土木工程师,这些定义就会破裂。如果你用它们来设计一个停车场,它会有一些令人讨厌的下雨的时候会挤在水里,并且会侵占邻居的财产。)

所以,你想要的是使用一个边界范围。假设您的纬度值a.lat和b.lat以度为单位,其中两个肯定超过五十法定英里,除非

     a.lat BETWEEN b.lat - 50.0/69.0 AND b.lat + 50.0/69.0

让我们重构您的查询。 (我不了解关于纽约的案例,所以我忽略了它。你可以把它添加回来。)这将给出彼此相距50英里的所有地方对的ID。 (我在这里使用21世纪的JOIN语法)。

select distinct a.id, b.id 
from latlon a
JOIN latlon b    ON a.id<>b.id
                AND a.lat BETWEEN b.lat - 50.0/69.0 AND b.lat + 50.0/69.0
                AND a.state = b.state
                AND geodist(a.lat,a.lon,b.lat,b.lon,"M") <= 50

尝试在lat列的表格上创建索引。这应该有助于表现很多。

然后尝试在(state,lat,id,lon,value)上创建复合索引。如果没有获得满意的性能加速,请尝试以不同的顺序在复合索引中使用这些列。它被称为覆盖索引,因为它的一些列(在这种情况下是前两个)用于快速查找,其余用于提供否则必须从主要提取的值表

答案 1 :(得分:0)

你的问题含糊不清 - 我把它解释为“给我所有(A,B)城市对在50英里之内。”纽约市特殊情况似乎是一次性测试 - 问题是(通常在O(n)时间内)找到纽约市50英里范围内的所有城市。

不是计算Great Circle距离,而是使用简单的加法和简单的边界框来找到曼哈顿距离。鉴于(A,B)城市元组Manhattan distance小于50英里,可以直接删除少数(在对角线上)大圆(或欧几里得)距离小于50英里。

您没有向我们显示描述后端优化程序计划的EXPLAIN输出。

您没有告诉我们latlon表上的索引。

我不熟悉SAS RDBMS。 Oracle,MySQL和其他人geospatial extensions支持多维索引。本质上,它们将高阶坐标位合并到低阶坐标位,以构造四叉树索引。该技术可以证明对您的查询有益。

您的DISTINCT关键字会对查询计划产生重大影响。通常它会强制执行tablescan和filesort。考虑删除它。

state上的等值连接似乎是错误的,但也许你不关心三州都市区和国家边界附近人口密集的地区。

您肯定希望WHERE子句删除距离当前b行超过50英里的a行:

  1. 向北太远,或者
  2. 南方太远,或者
  3. 西边太远,或者
  4. 太远的东方
  5. 这些条件中的每一个都归结为一个简单的范围查询,RDBMS后端可以根据索引对其进行评估和优化。不幸的是,如果它选择了纬度指数,那么磁盘上的任何经度索引都将被忽略,反之亦然。这促使您使用供应商的地理空间支持。