2014-06-30 203 views
1

我目前有一個大表mivehdetailedtrajectory(25B行)和一個小表cell_data_tower(400行),我需要使用PostGIS加入。具體來說,我需要運行這個查詢:優化大型PostGIS查詢

SELECT COUNT(traj.*), tower.id 
FROM cell_data_tower tower LEFT OUTER JOIN mivehdetailedtrajectory traj 
ON ST_Contains(tower.geom, traj.location) 
GROUP BY tower.id 
ORDER BY tower.id; 

它錯誤出來生氣,它不能寫入磁盤。這似乎是不可思議的選擇,所以我跑了說明: 注意:gserialized_gist_joinsel:jointype 1不支持

             QUERY PLAN              
-------------------------------------------------------------------------------------------------------------------- 
Sort (cost=28905094882.25..28905094883.25 rows=400 width=120) 
    Sort Key: tower.id 
    -> HashAggregate (cost=28905094860.96..28905094864.96 rows=400 width=120) 
     -> Nested Loop Left Join (cost=0.00..28904927894.80 rows=33393232 width=120) 
       Join Filter: ((tower.geom && traj.location) AND _st_contains(tower.geom, traj.location)) 
       -> Seq Scan on cell_data_tower tower (cost=0.00..52.00 rows=400 width=153) 
       -> Materialize (cost=0.00..15839886.96 rows=250449264 width=164) 
        -> Seq Scan on mivehdetailedtrajectory traj (cost=0.00..8717735.64 rows=250449264 width=164) 

我不明白爲什麼Postgres的認爲它應該兌現內部表。另外,我不明白一般的計劃是誠實的。似乎應該將cell_data_tower表保存在內存中,並遍歷mivehdetailedtrajectory表。關於如何優化這個(a)運行,(b)在合理的時間內這樣做的任何想法。具體來說,這似乎應該在不到1天的時間內完成。

編輯:需要大量內存的Postgres 9.3版

+0

請添加PostgreSQL的版本。 –

+0

可能是一個愚蠢的問題,但你確實有一個mivehdetailedtrajectory空間索引?在這種查詢中,你並不需要編寫左外連接,因爲本質上你正在進行完全連接,但是通過「空間」連接來限制結果。如果用逗號替換左外連接,則可能會得到不同的計劃。 –

+0

我有類似的問題與磁盤空間用散列連接。您可以嘗試設置enable_hashagg = off和/或enable_hashjoin = off。這可能會使查詢計劃變得更糟(它的確如此),但它會切換到使用嵌套循環連接,儘管速度較慢,但​​不會嚼碎磁盤空間。最終,如果你沒有空間索引,那麼你無論如何都要做一個雙循環,每次只檢查ST_Contains。正如Jakub指出的那樣,我冒昧地爲您的選擇添加了tower.id。 –

回答

0

查詢是罕見的地方,相關子查詢執行得更好(LATERAL JOIN應太,但這些都是超越我)。另外請注意,你沒有選擇tower.id,所以你的結果不會太有用。

SELECT tower.id, (SELECT COUNT(traj.*) 
        FROM mivehdetailedtrajectory traj 
        WHERE ST_Contains(tower.geom, traj.location)) 
FROM cell_data_tower tower 
ORDER BY tower.id; 

先試着用LIMIT 1先運行它。總運行時間應該是一個塔*塔數的運行時間。

0

我沒有像你這麼大的db,只有80M。但在我的情況下,我創建一個LinkID字段來知道每個geom在哪裏,並計算哪一個是最接近的LinkID,當我插入一條新的記錄。

當我發現一個LinkID需要30ms,做80M次需要27天,我從預先計算這些值。

另外我不保留所有的記錄,我只保留一個月在任何時間。