我的任务是改进缓慢运行的进程的性能,该进程更新PostGres 8.3数据库中的某些数据(在Solaris上运行,更新由Perl 5.8脚本通过SOAP驱动)。大约50%的时间消耗我几乎无法控制,所以调整我的50%非常重要。
表中通常有大约4,500,000行,但我看到它膨胀到大约7,000,000。更新正在查询的ID(非主要或唯一)具有不到9000个不同的值,并且出现的扩散大量加权为每个id 1(中值为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;
我意识到'不是空'远非理想。 Id被编入索引作为发票和&amp;客户端(btree,所以我理解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
我相信Autovacuum已启用。没有外键约束,但感谢提示,因为我不知道。
我真的很喜欢增加统计数据的想法 - 我马上就会玩这个。
答案 0 :(得分: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的找到次数。
存储这么多最常见的值会产生性能成本,因此您确实需要支持查询计划分析来确定您是否获得净收益。