特定のディレクトリに配置されたcsvファイルからすべての行を自動的に取得し、それらをテーブルにインポートするバックグラウンドプロセス(無限ループのLinuxデーモン)があります。デーモンは、ディレクトリに表示されるファイルを 1 つずつ処理し、python で記述され、psycopg2 を使用して postgresql データベースに接続します。
このプロセスでは、INSERT ステートメントを使用してこれらのレコードをインポートしますが、最初に csv ファイル内のレコードと同じ一意のキーを持つすべてのテーブル レコードを削除します。一般に、プロセスは、挿入するすべてのレコードのレコードを削除します。したがって、このデーモンはバックグラウンドで実行されているため、行を削除してから挿入します。1 つのファイルを処理するたびに、明確にトランザクションをコミットし、カーソルを閉じてから、接続を閉じます。
定期的に (1 日に 2 回) 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)