PostgreSQL - トランザクション ブロックの外のコードから VACUUM を実行するにはどうすればよいですか?
-
06-07-2019 - |
質問
psycopg2 で Python を使用しており、完全な VACUUM
数千行を挿入する毎日の操作の後。問題は、を実行しようとすると、 VACUUM
コード内でコマンドを実行すると、次のエラーが発生します。
psycopg2.InternalError: VACUUM cannot run inside a transaction block
トランザクション ブロックの外側のコードからこれを実行するにはどうすればよいですか?
違いがある場合は、単純な DB 抽象化クラスを用意します。そのサブセットをコンテキストのために以下に示します (実行不可、例外処理と docstring が省略され、行範囲の調整が行われています)。
class db(object):
def __init__(dbname, host, port, user, password):
self.conn = psycopg2.connect("dbname=%s host=%s port=%s \
user=%s password=%s" \
% (dbname, host, port, user, password))
self.cursor = self.conn.cursor()
def _doQuery(self, query):
self.cursor.execute(query)
self.conn.commit()
def vacuum(self):
query = "VACUUM FULL"
self._doQuery(query)
解決
さらに検索した結果、psycopg2接続オブジェクトのisolation_levelプロパティが見つかりました。これを 0
に変更すると、トランザクションブロックから移動することがわかります。上記のクラスの真空メソッドを次のように変更すると解決します。また、分離レベルを以前のケースに戻しました(デフォルトでは 1
のようです)。
def vacuum(self):
old_isolation_level = self.conn.isolation_level
self.conn.set_isolation_level(0)
query = "VACUUM FULL"
self._doQuery(query)
self.conn.set_isolation_level(old_isolation_level)
この記事(そのページの終わり近く)に、分離の簡単な説明があります。このコンテキストのレベル。
他のヒント
さらに、以下を使用して、バキュームまたは分析によって提供されるメッセージを取得することもできます。
>> print conn.notices #conn is the connection object
このコマンドは、VacuumやAnalyseなどのクエリのログメッセージを含むリストを出力します。
INFO: "usuario": processados 1 de 1 páginas, contendo 7 registros vigentes e 0 registros não vigentes; 7 registros amostrados, 7 registros totais estimados
INFO: analisando "public.usuario"
これは、DBAにとって有用な場合があります^^
postgresqlの現在のバージョンではバキュームフルは疑わしいですが、特定の大規模なアクションがパフォーマンスを改善したり、ディスク使用量をクリーンアップしたりした後、「バキューム分析」または「リインデックス」を強制します。これはpostgresql固有であり、他のデータベースに対して正しいことを行うためにクリーンアップする必要があります。
from django.db import connection
# Much of the proxy is not defined until this is done
force_proxy = connection.cursor()
realconn=connection.connection
old_isolation_level = realconn.isolation_level
realconn.set_isolation_level(0)
cursor = realconn.cursor()
cursor.execute('VACUUM ANALYZE')
realconn.set_isolation_level(old_isolation_level)
残念ながら、djangoが提供する接続プロキシはset_isolation_levelへのアクセスを提供しません。
DjangoをSouthで使用して移行を実行している場合、次のコードを使用して VACUUM ANALYZE
を実行できます。
def forwards(self, orm):
db.commit_transaction()
db.execute("VACUUM ANALYZE <table>")
#Optionally start another transaction to do some more work...
db.start_transaction()
私は psycopg2 と PostgreSQL は知りませんが、apsw と SQLite しか知りません。そのため、「psycopg2」のヘルプは提供できないと思います。
しかし、PostgreSQL は SQLite と同様に動作するのではないかと私には思われます。PostgreSQL には 2 つの動作モードがあります。
- トランザクションブロックの外側:これは、単一の SQL 操作ごとにトランザクション ブロックを配置することと意味的に同等です。
- 「BEGIN TRANSACTION」でマークされ、「END TRANSACTION」で終了するトランザクション ブロック内
この場合、問題はアクセス レイヤ psycopg2 の内部にある可能性があります。通常、コミットが行われるまでトランザクションが暗黙的に挿入される方法で動作する場合、バキュームを作成する「標準的な方法」は存在しません。
もちろん、「psycopg2」が特別な「バキューム」メソッド、または暗黙的なトランザクションが開始されない特別な操作モードを備えている可能性もあります。
そのような可能性が存在しない場合、(アクセス層を変更せずに ;-) )、単一のオプションが残ります。
ほとんどのデータベースには、データベースにアクセスするためのシェル プログラムがあります。プログラムはパイプを使用してこのシェル プログラムを実行し (シェルに真空コマンドを入力)、シェル プログラムを使用して真空を作成できます。バキューム自体は遅い操作であるため、外部プログラムの開始は無視できるほどです。もちろん、実際のプログラムは、コミットされていないすべての作業を事前にコミットする必要があります。そうしないと、デッドロック状況が発生する可能性があります。バキュームは、最後のトランザクションが終了するまで待機する必要があります。
それをしないでください-VACUUM FULLは必要ありません。実際、Postgresのやや最近のバージョン(たとえば&gt; 8.1)を実行する場合、プレーンなVACUUMを手動で実行する必要さえありません。