您好我有一个模拟快照,当前存储在PostgreSQL数据库中作为快照表的架构的表
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我的机器本地。
答案 0 :(得分: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 JOIN(可能是EXPLAIN
或更好EXPLAIN ANALYZE
确定),查询速度太慢,那么一种不同的方法肯定会保证对大型扫描的单次扫描table是将所有结果收集到一行中,每个半径一列,生成的查询如下所示:
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
如果不实用,可能值得尝试的另一种完全不同的方法是在 btree功能索引中预先计算SQRT(x^2 + y^2 + z^2)
,希望SQL引擎可以使用它与不平等比较。是否发生这种情况以及查询是否更快取决于数据分布。
create index radius_idx on isonew_4.snapshot_102(SQRT(x^2 + y^2 + z^2));
然后使用第一个查询,每次重复单个半径,或者使用GROUP BY
的方法#1和所有值一次重复。如果值非常有选择性,则执行速度可能比单个大型顺序扫描更快。