2

我们有一个后台进程(无限循环中的 linux 守护进程),它自动从 csv 文件中获取所有行,这些文件位于某个目录中,并将它们导入到表中。守护进程一一处理目录中出现的任何文件,用python编写,并使用psycopg2连接到我们的postgresql数据库。

该过程使用 INSERT 语句导入这些记录,但首先删除与 csv 文件中的任何记录具有相同唯一键的任何表记录。通常,该过程正在删除它插入的每条记录的记录。因此,当这个守护进程在后台运行时,它是 DELETING 然后 INSERTING 行。每次它处理一个文件时,它都会专门提交事务,关闭游标,然后关闭连接。

我们希望定期(每天两次)运行 CLUSTER 以删除死元组并将表保持在可管理的磁盘大小。

但是,此过程中的某些内容正在阻止 CLUSTER 命令删除进程运行时正在删除的所有记录的死元组。我们知道会发生这种情况,因为如果我们在进程运行时运行 CLUSTER,包含此导入数据的表的磁盘大小不会减少,并且 pg_stat_user_tables 将显示许多死元组。

如果我们停止进程然后运行 ​​CLUSTER,表的磁盘大小将显着减小,并且 pg_stat_user_tables 将报告所有死元组都已消失。

奇怪的是,我们每次处理每个文件时都在提交事务并关闭连接,所以我不知道是什么不允许在进程运行时删除死元组。

同样奇怪的是,如果我们停止该进程,然后再次启动该进程,然后执行一个 CLUSTER,它将删除之前运行守护进程创建的所有死元组;但是任何后续的 CLUSTER 调用都不会清除当前运行的守护进程创建的任何死元组(当然它仍在运行)。

因此,在进程停止之前,有些东西正在维护到死元组的某种链接,即使我们已经提交了事务并关闭了与创建这些死元组的 postgres 的所有连接。pg_locks 没有报告任何打开的锁,也没有报告正在运行的事务,所以它看起来不像是锁或打开的事务问题。

归根结底,这会阻止我们在表上定期运行 CLUSTER,以免它不断增长。

我确信对此有一个简单的答案,但我在任何地方都找不到。该过程的一些骨架代码如下。这确实是一个简单的过程,所以我不知道这里发生了什么。任何指导将不胜感激。

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)
4

1 回答 1

2

自动吸尘器有什么问题?当 autovacuum 完成它的工作时,您不必使用 CLUSTER 来清理死元组。CLUSTER 不是为此而生的,它是 VACUUM。

如果您将过程更改为 UPDATE 副本,则当您使用较低的 FILLFACTOR: HOT 更新时,情况可能会变得更好。这些更快,回收空间,保持相同的存储顺序,不需要 VACUUM 或 CLUSTER。

于 2011-01-14T08:28:21.883 回答