我经常在两个大型数据集上运行两种类型的查询。它们的运行速度比我预期的要慢得多。
第一种类型是顺序扫描更新所有记录:
Update rcra_sites Set street = regexp_replace(street,'/','','i')
rcra_sites有700,000条记录。 pgAdmin需要22分钟!我编写了一个vb.net函数,它循环遍历每条记录,并为每条记录发送更新查询(是的,700,000个更新查询!),它运行的时间不到一半。嗯....
第二种类型是带关系的简单更新,然后是顺序扫描:
Update rcra_sites as sites
Set violations='No'
From narcra_monitoring as v
Where sites.agencyid=v.agencyid and v.found_violation_flag='N'
narcra_monitoring有1,700,000条记录。这需要8分钟。查询计划程序拒绝使用我的索引。如果我从 set enable_seqscan = false; 开始,查询运行得更快。如果查询规划器能够完成它的工作,我更愿意。
我有适当的索引,我已经吸尘并进行了分析。我优化了 shared_buffers 和 effective_cache_size ,因为我有4GB,所以我知道要使用更多内存。我的硬件非常好。我在Windows 7上运行v8.4。
PostgreSQL这么慢吗?或者我还缺少什么?
答案 0 :(得分:1)
与seq_page_cost相比,可能会尝试减少random_page_cost(默认值:4):这会降低规划者对seq扫描的偏好,方法是使索引驱动的随机访问更具吸引力。
要记住的另一件事是MVCC意味着更新一行相当昂贵。特别是,更新表中的每一行都需要将表的存储量加倍,直到可以对其进行清理。因此,在您的第一个查询中,您可能希望限定更新:
UPDATE rcra_sites Set street = regexp_replace(street,'/','','i')
where street ~ '/'
(afaik postgresql不会自动抑制更新,如果它看起来你实际上没有更新任何东西.Istr有一个标准的触发器功能在8.4(?)中添加,以允许你这样做,但它可能更好的在客户端解决它)
答案 1 :(得分:0)
更新行时,会写入新的行版本。
如果新行不适合同一磁盘块,则需要更新指向旧行的每个索引条目以指向新行。
不仅需要更新更新数据的索引。
如果rcra_sites
上有很多索引,并且只有一两个经常更新的字段,那么您可以通过将经常更新的字段分成自己的表来获得。
您还可以将fillfactor
百分比降低到默认值100以下,以便某些更新可能导致新行被写入同一个块,从而导致指向该块的索引不需要更新。