2015-01-08 67 views
1

您好我已經得到了當前存儲在PostgreSQL數據庫的模擬快照作爲錶快照表的模式是高效運行在多個輸入的SQL查詢

simdb=> \d isonew_4.snapshot_102 
Table "isonew_4.snapshot_102" 
Column | Type | Modifiers 
--------+---------+----------- 
id  | integer | 
x  | real | 
y  | real | 
z  | real | 
vx  | real | 
vy  | real | 
vz  | real | 
pot | real | 
mass | real | 
Indexes: 
    "snapshot_102_id_idx" btree (id) WITH (fillfactor=100) 

我有一個查詢計算封閉精細單一半徑的質量:

SELECT SUM(mass) AS mass 
FROM isonew_4.snapshot_102 AS s 
WHERE SQRT(s.x^2 + s.y^2 + s.z^2) < {radius} 

但是我想在不同半徑的數數運行此。

由於該表擁有大約1億行,因此我寧願將其作爲SQL查詢來執行,而不是抓取所有的粒子,並在Python中使用類似numpy.histogram的內容在本地對我的計算機執行binning操作。

回答

2

方法#1

該查詢可能工作,具有例如10,20和25作爲半徑的連續值:

WITH r(radius) as (values (10),(20),(25)) 
    SELECT radius, SUM(mass) AS mass 
    FROM isonew_4.snapshot_102 AS s CROSS JOIN r 
    WHERE SQRT(s.x^2 + s.y^2 + s.z^2) < radius 
    GROUP BY radius; 

輸出具有兩列:radius和對應sum(mass)


方法2

如果查詢太慢,因爲CROSS與列表(大概EXPLAIN或更好EXPLAIN ANALYZE會肯定地告訴)JOIN,採用不同的方法肯定保證了大表的一次掃描是收集在一個單一的行中的所有結果,每一個半徑柱,以尋找這樣的產生查詢

SELECT 
sum(case when r < 10 then s.mass else 0 end) as radius10, 
sum(case when r < 20 then s.mass else 0 end) as radius20, 
sum(case when r < 25 then s.mass else 0 end) as radius25 
FROM (select mass,SQRT(x^2 + y^2 + z^2) as r from isonew_4.snapshot_102) AS s 

方法#3

如果它是不實際的,另一種完全不同的方式,可能是值得嘗試將預先計算SQRT(x^2 + y^2 + z^2)B樹函數索引在希望SQL引擎在不平等比較中使用它。這種情況是否發生,以及查詢是否會更快取決於數據分佈。

create index radius_idx on isonew_4.snapshot_102(SQRT(x^2 + y^2 + z^2)); 

然後使用第一查詢,要麼每次用單個半徑,或方法#1與GROUP BY並一次所有值重複。如果這些值非常具有選擇性,那麼執行速度可能會比單次大型順序掃描更快。

+0

感謝您的輸入,但這看起來比較慢(似乎在O(n)時間內運行的半徑數量是兩倍)。我看看使用[this](https://wiki.postgresql.org/wiki/Aggregate_Histogram)作爲基礎。如果有任何問題,我會更新這個問題。 –

+0

這是可能的。我爲執行速度添加了其他選項。 –