2017-03-21 11 views
1

私は緯度と経度で距離を計算しているので、特定の場所から2km以内の人の数量を取得しようとしています。 1つのテーブルで私はちょうど緯度と経度を持っていて、他にはもっと多くのフィールドがありますが、緯度と経度もあります。緯度と経度の距離を計算するパフォーマンスが低い

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

クエリが有効であるとするとき、実行12.3メガバイトを処理します。

私が使用しているクエリは次のとおりです。

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分かかります:類似したに

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 

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の不平等を変換しなければならなかった

(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 

我々は非常に類似した結果を得るが、中2分ではなく12秒。

サンプルテーブルの番号や行数や列数が同じではないため、正確なクエリを最適化することはできませんが、完全なクロスジョインの前にこれらの「サニティJOINチェック」を適用しようとしています。

+1

ありがとう、@フェリペ!私は、プロダクションデータセットのニーズを満たすためにクエリを少し変更しましたが、あなたのトリックで作業が可能になりました! –

2

距離の述語にJOINを使用してこの種のブルートフォース分析を行うと、良好なパフォーマンスが得られません。 BigQueryチームは、地理空間分析のサポートを強化することを検討しています(述語にST_DWithin関数を使用)。その間、Postgresにドロップし、PostGISエクステンションを使用するのがおそらく最善の策です。

+2

BigQueryで地理空間分析に興味を持っている人は、これらの機能の可用性に関するアップデートを入手するにはどうすればよいですか? –

関連する問題