Chr*_*ell 4 sql postgresql energy
我正在与一家在美国制定太阳能潜力的非营利组织合作.不用说,我们有一个可笑的大型PostgreSQL 9数据库.运行如下所示的查询是快速的,直到该order by行被取消注释,在这种情况下相同的查询需要永远运行(185毫秒没有排序,相比之下25分钟).应该采取哪些步骤来确保在更加可管理和合理的时间内运行此查询和其他查询?
select A.s_oid, A.s_id, A.area_acre, A.power_peak, A.nearby_city, A.solar_total
from global_site A cross join na_utility_line B
where (A.power_peak between 1.0 AND 100.0)
and A.area_acre >= 500
and A.solar_avg >= 5.0
AND A.pc_num <= 1000
and (A.fips_level1 = '06' AND A.fips_country = 'US' AND A.fips_level2 = '025')
and B.volt_mn_kv >= 69
and B.fips_code like '%US06%'
and B.status = 'active'
and ST_within(ST_Centroid(A.wkb_geometry), ST_Buffer((B.wkb_geometry), 1000))
--order by A.area_acre
offset 0 limit 11;
Run Code Online (Sandbox Code Playgroud)
排序不是问题 - 实际上排序的CPU和内存成本接近于零,因为Postgres具有Top-N排序,其中扫描结果集,同时保持最新仅包含前N行的小排序缓冲区.
select count(*) from (1 million row table) -- 0.17 s
select * from (1 million row table) order by x limit 10; -- 0.18 s
select * from (1 million row table) order by x; -- 1.80 s
Run Code Online (Sandbox Code Playgroud)
所以你看到Top-10排序只增加了10毫秒到一个哑快速计数(*)而不是更长的真实排序.这是一个非常简洁的功能,我经常使用它.
好吧,现在没有EXPLAIN ANALYZE,这是不可能确定的,但我的感觉是真正的问题是交叉连接.基本上你使用以下方法过滤两个表中的行:
where (A.power_peak between 1.0 AND 100.0)
and A.area_acre >= 500
and A.solar_avg >= 5.0
AND A.pc_num <= 1000
and (A.fips_level1 = '06' AND A.fips_country = 'US' AND A.fips_level2 = '025')
and B.volt_mn_kv >= 69
and B.fips_code like '%US06%'
and B.status = 'active'
Run Code Online (Sandbox Code Playgroud)
好.我不知道在两个表中选择了多少行(只有EXPLAIN ANALYZE会告诉),但它可能很重要.知道这些数字会有所帮助.
然后我们得到了最糟糕的CROSS JOIN条件:
and ST_within(ST_Centroid(A.wkb_geometry), ST_Buffer((B.wkb_geometry), 1000))
Run Code Online (Sandbox Code Playgroud)
这意味着A的所有行都与B的所有行匹配(因此,这个表达式将被大量计算),使用一堆非常复杂,缓慢和CPU密集的函数.
当然,它非常慢!
当你删除ORDER BY时,postgres刚出现(偶然?),在开始时有一堆匹配的行,输出那些,并且自达到LIMIT后停止.
这是一个小例子:
表a和b是相同的,包含1000行,以及BOX类型的列.
select * from a cross join b where (a.b && b.b) --- 0.28 s
Run Code Online (Sandbox Code Playgroud)
这里1000000箱重叠(操作员&&)测试在0.28s内完成.生成测试数据集,以便结果集仅包含1000行.
create index a_b on a using gist(b);
create index b_b on a using gist(b);
select * from a cross join b where (a.b && b.b) --- 0.01 s
Run Code Online (Sandbox Code Playgroud)
这里索引用于优化交叉连接,速度很荒谬.
您需要优化几何匹配.
在CROSS JOIN期间重新计算这些慢速函数一百万次没有任何要点,因此将结果存储在一列中.使用触发器使它们保持最新.
添加将缓存的BOX类型的列:
在BOX上添加gist索引
添加一个Box重叠测试(使用&&运算符),它将使用索引
保留你的ST_Within,它将作为通过的行的最终过滤器
也许您可以只索引ST_Centroid和ST_Buffer列...并使用(索引)"包含"运算符,请参见此处:
http://www.postgresql.org/docs/8.2/static/functions-geometry.html
| 归档时间: |
|
| 查看次数: |
268 次 |
| 最近记录: |