用纬度和经度计算距离的性能不佳

时间:2017-03-21 21:00:04

标签: google-bigquery google-cloud-platform

我试图从特定位置获取2公里或更少的人数,为此我计算了纬度和经度的距离。在一张桌子中我只有纬度和经度,而在另一张桌子里我有更多的田地,但也有纬度和经度。

  • 表1 = 488792行
  • 表2 = 63003行

查询有效,运行时将处理12.3 MB。

我使用的查询是:

select 
e.lat,
e.long,
e.searches,
count(distinct l.id)
from dataset.table1 e
join dataset.table2 l 
     on 6371000*ACOS(COS(3.14159265359/180*(90-e.lat)) *COS(3.14159265359/180*(90-l.lat)) +SIN(3.14159265359/180*(90-e.lat)) *SIN(3.14159265359/180*(90-l.lat)) *COS(3.14159265359/180*(e.long-l.long))) <= 2000 # way to calculate distance from lats and longs
group by e.lat,
e.long,
e.searches

但是查询没有运行,每次都需要超过15分钟,我必须取消。

可能是什么问题?

2 个答案:

答案 0 :(得分:5)

此查询与原始查询类似,需要2分钟:

SELECT distance, COUNT(*) FROM (
SELECT
  e.lat,
  e.long
  , 6371000*ACOS(COS(3.14159265359/180*(90-e.lat)) *COS(3.14159265359/180*(90-l.lat)) +SIN(3.14159265359/180*(90-e.lat)) *SIN(3.14159265359/180*(90-l.lat)) *COS(3.14159265359/180*(e.long-l.long))) <= 2000 distance
  , e.long-l.long longlong, e.lat-l.lat latlat
FROM
  `buoyant-history-159518.test_lat_long.table1` e
JOIN
  `buoyant-history-159518.test_lat_long.table1` l
ON 
 (COS(3.14159265359/180*(90-e.lat)) *COS(3.14159265359/180*(90-l.lat)) +SIN(3.14159265359/180*(90-e.lat)) *SIN(3.14159265359/180*(90-l.lat)) *COS(3.14159265359/180*(e.long-l.long))) <= COS(2000/6371000) + 4.5E-8
)
GROUP BY distance

为了防止浮点错误,我不得不改变JOIN不等式:

6371000*ACOS(COS(3.14159265359/180*(90-e.lat)) *COS(3.14159265359/180*(90-l.lat)) +SIN(3.14159265359/180*(90-e.lat)) *SIN(3.14159265359/180*(90-l.lat)) *COS(3.14159265359/180*(e.long-l.long))) 
<= 2000

到类似的:

(COS(3.14159265359/180*(90-e.lat)) *COS(3.14159265359/180*(90-l.lat)) +SIN(3.14159265359/180*(90-e.lat)) *SIN(3.14159265359/180*(90-l.lat)) *COS(3.14159265359/180*(e.long-l.long))) <= COS(2000/6371000) + 4.5E-8)
<= COS(2000/6371000) + 4.5E-8

现在问题是我们如何才能获得比2分钟更好的表现?让我们加入一些“理智”的理智。过滤器 - &gt;在同一区域内没有2个点可以在拉特之间有一个距离,长度大于0.something:

SELECT distance, COUNT(*) FROM (
SELECT
  e.lat,
  e.long
  , (COS(3.14159265359/180*(90-e.lat)) *COS(3.14159265359/180*(90-l.lat)) +SIN(3.14159265359/180*(90-e.lat)) *SIN(3.14159265359/180*(90-l.lat)) *COS(3.14159265359/180*(e.long-l.long))) <= COS(2000/6371000) distance
  , e.long-l.long longlong, e.lat-l.lat latlat
FROM
  `buoyant-history-159518.test_lat_long.table1` e
JOIN
  `buoyant-history-159518.test_lat_long.table1` l
ON 
 NOT (e.long=l.long AND e.lat=l.lat) 
 AND ABS(e.long-l.long) < 0.021 #sanity JOIN check
 AND ABS(e.lat-l.lat) < 0.018 #sanity JOIN check
)
GROUP BY distance

有了这个,我们得到非常相似的结果,但在12秒而不是2分钟。

我无法优化您的确切查询,因为您的示例表格不具有相同的数字或行数或列数 - 但尝试应用这些&#34;完整性JOIN检查&#34;在进行完整的CROSS JOIN之前。

答案 1 :(得分:2)

使用JOIN对距离谓词进行这种强力分析并不会有很好的表现。 BigQuery团队正在考虑为地理空间分析添加更好的支持(即在ST_DWithin谓词中使用JOIN函数)。与此同时,放入Postgres并使用PostGIS扩展可能是您最好的选择。