2017-03-21 241 views
1

我想從特定位置獲得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分鐘,我不得不取消。

可能是什麼問題?

+0

全表掃描可能是問題所在。您需要使用良好的索引,並且看起來您有一個非常複雜的連接。任何或所有這些事情都可能是負責任的。 – mba12

+0

你能提供一個樣本數據集嗎?我想玩優化這個查詢,但我需要一個合適的測試牀 –

+0

當然@FelipeHoffa,我怎麼能送你?謝謝! –

回答

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分鐘更好的性能?讓我們增加了加入一些「理智」過濾器 - >無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分鐘。

我無法優化您的確切查詢,因爲您的示例表沒有相同的數量或行數,也沒有列數 - 但在進行完整的CROSS JOIN之前嘗試應用這些「完整性JOIN檢查」。

+1

非常感謝,@ Felipe!爲了滿足我們在生產數據集中的需求,我改變了一些查詢,但是你的技巧使它有可能工作! –

2

做這種使用JOIN的蠻力分析對於距離謂詞不會有很好的表現。 BigQuery團隊正在考慮爲地理空間分析添加更好的支持(即使用JOIN謂詞中的ST_DWithin函數)。與此同時,放入Postgres並使用PostGIS擴展可能是您最好的選擇。

+2

作爲對BigQuery中的地理空間分析感興趣的人,我如何獲得這些功能的可用性更新? –

相關問題