2009-11-03 122 views
0

我的任务是提高缓慢运行进程的性能,该进程更新PostGres 8.3数据库(在Solaris上运行,更新由Perl 5.8脚本通过SOAP驱动)中的一些数据。大约50%的时间消耗我很少控制,所以调整我的50%是非常重要的。性能优化 - Postgres

表中通常有大约4,500,000行,尽管我已经看到它膨胀到约700万。更新查询的ID(不是主要的或唯一的)具有近9000个不同的值,并且事件的传播对每个ID大量加权(中值为20,最大值为7000)。

这个ID有一个索引,但有这样稀疏的数据我不知道是否有更好的方法做事情。我也在考虑对数据进行非规范化处理(无论如何,数据库并没有超标准化)&将数据拉出到单独的表格中(可能由触发器控制/维护)以帮助加快速度。

到目前为止,我已经做了一些非常基本的调整(不是每n秒钟ping数据库以查看它是否存在,不会不必要地设置会话变量等),这是有帮助的,但我真的觉得有些东西我缺少与数据...

即使有人说,拉出相关数据到一个单独的表是一个很好的/可怕的想法,这将是非常有益的!任何其他想法(或进一步的澄清问题)感激地收到!

查询:

UPDATE tab1 SET client = 'abcd', invoice = 999 
    WHERE id = 'A1000062' and releasetime < '02-11-09'::DATE 
    AND charge IS NOT NULL AND invoice IS NULL AND client IS NULL; 

我意识到 '不为空' 是远远不够理想。编号索引,发票&客户端(btrees,所以我明白PostGres将/应该/可以使用索引那里)。这是一个很琐碎的查询......

查询计划(与分析讲解):

Bitmap Heap Scan on tab1 (cost=17.42..1760.21 rows=133 width=670) (actual time=0.603..0.603 rows=0 loops=1) 
    Recheck Cond: (((id)::text = 'A1000062'::text) AND (invoice IS NULL)) 
    Filter: ((charge IS NOT NULL) AND (client IS NULL) AND (releasetime < '2009-11-02'::date)) 
    -> Bitmap Index Scan on cdr_snapshot_2007_09_12_snbs_invoice (cost=0.00..17.39 rows=450 width=0) (actual time=0.089..0.089 rows=63 loops=1) 
    Index Cond: (((snbs)::text = 'A1000062'::text) AND (invoice IS NULL)) 
Total runtime: 0.674 ms 

自动清理的,我相信,启用。没有外键约束,但感谢提示,因为我不知道这一点。

我真的很喜欢增加统计值的想法 - 我马上就会玩一玩。

+1

查询计划是什么样子的,您是否启用了autovacuum或是否定期执行真空(不运行autovacuum)。 – 2009-11-03 08:10:31

回答

0

您确实需要获取一些查询计划,并编辑您的问题以包含它们。除了帮助找出更好的方法之外,还可以用它们来轻松衡量改进情况。


您可以通过更改SQL或通过调整用于确定查询计划的索引和统计信息来影响性能。


一种可能性是您有没有支持索引的外键约束。当您创建外键约束时,PostgreSQL不会自动添加它们。如果被引用的表有一行被删除(或被引用的字段被更新),则引用表将需要完全扫描,以级联删除或确保没有引用已删除行的行。


如果你的id字段的分布是相当偏斜,该列增加统计数据可能帮助。

如果统计数据设置为100,则会记录100个最常见的ID(来自样本)以及它们的频率。假设覆盖了大约50%的表格,剩下2到350万行PostgreSQL会假设其他8900个ID, 或每个大约250到400次。

如果统计数据增加到1000,前1000个ID覆盖你行的95%,PostgreSQL将假设不在你列表中的1000个最常见的ID将会出现大约30到40次。

估算值的变化会影响选定的查询计划。如果查询模式更频繁地选择不太经常发现的id的id,PostgreSQL将过度估计id将被发现的次数。

存储这么多最常见的值会带来性能成本,因此您确实需要支持查询计划分析以确定您是否获得净收益。