我们有一个后台进程(无限循环中的linux守护进程),它自动从放在某个目录中的csv文件中获取所有行,并将它们导入到一个表中。守护进程一个接一个地处理目录中的任何文件,这些文件是用python编写的,并使用psycopg2连接到我们的postgresql数据库。
该过程使用INSERT语句导入这些记录,但首先删除与csv文件中的任何记录具有相同唯一键的任何表记录。通常情况下,进程是为它插入的每一个记录删除一个记录。因此,当这个守护进程在后台运行时,它将删除并插入行。每次它处理一个文件时,它都会特别提交事务,关闭游标,然后关闭连接。
我们希望定期(每天两次)运行集群,以删除死元组,并将表保持在磁盘大小上的可管理范围内。
但是,此过程中的某些内容阻止群集命令删除进程运行时删除的所有记录的死元组。我们知道这种情况是因为如果我们在进程运行时运行集群,包含这些导入数据的表的磁盘上大小不会减少,而且pg_stat_user_tables将显示许多死元组。
如果我们停止进程,然后运行集群,表的磁盘上大小就会急剧减少,并且pg_stat_user_tables会报告所有死元组都消失了。
奇怪的是,每次处理每个文件时,我们都要提交事务并关闭连接,所以我不知道什么不允许在进程运行时删除死元组。
同样奇怪的是,如果我们停止进程,然后再次启动进程,然后执行集群,它将删除由上一次运行守护进程创建的所有死元组;但是,集群的任何后续调用都不会清除当前运行的守护进程创建的任何死元组(当然,它仍然在运行)。
因此,有些东西在进程停止之前维护到死元组的某种链接,即使我们已经提交了事务并关闭了与生成这些死元组的postgres的所有连接。pg_locks不报告任何打开的锁,也没有报告正在运行的事务,因此它看起来不像是一个锁或打开的事务问题。
到头来,这阻止了我们定期在桌面上运行集群,这样它就不会继续增长。
我相信有一个简单的答案,但我在任何地方都找不到。流程的一些基本代码如下所示。这真的是一个简单的过程,所以我不知道这里发生了什么。如有任何指导,将不胜感激。
while True:
l = [(get_modified_time(fname), fname) for fname in os.listdir('/tmp/data')]
l.sort()
for (t, fname) in l:
conn = psycopg2.connect("dbname='dbname' user='user' password='password'")
cursor = conn.cursor()
# Calls a postgresql function that reads a file and imports it into
# a table via INSERT statements and DELETEs any records that have the
# same unique key as any of the records in the file.
cursor.execute("SELECT import('%s', '%s');" % (fname, t))
conn.commit()
cursor.close()
conn.close()
os.remove(get_full_pathname(fname))
time.sleep(0.100)发布于 2011-01-14 08:28:21
自动吸尘器怎么了?当自动真空完成它的工作时,您不必使用集群来清理死元组。星系团不是用来做这个的,而是真空的。
如果您将过程更改为更新副本,则使用较低的FILLFACTOR:热更新时,情况可能会更好。这些是更快,回收空间,保持相同的顺序在存储和不需要真空或集群。
https://stackoverflow.com/questions/4686541
复制相似问题