時々、ORMを使用する代わりに connection.cursor()
を使用して生のクエリを実行しています(これは間違いなく特効薬ではないため)。
データベースを使い終わった後、いくつかの場所で明示的なcursor.close()
を呼び出さないことに気づきました。これまでのところ、これによってエラーやパフォーマンスの問題が発生することはありません。カーソルを明示的に閉じないと、どのような問題が発生する可能性があるのでしょうか。
私が理解している限り、connection
およびcursor
in Django follow "Python Database API Specification v2.0"( PEP-249 =)そして、それによると、cursor
は__del__()
メソッドが呼び出されるたびに自動的に閉じられます。
参考までに、Python 2.7およびDjango 1.6.5。
___del__
_/.close()
:
__del__
_の呼び出しは保証されていません__del__
_でcursor.close()を呼び出さない(不適切な方法ですが、true)サーバー接続全般
ほとんどのサーバーには、アイドルタイムアウト構成プロパティがあります(Tと呼びましょう)。接続がT秒以上アイドル状態の場合、サーバーは接続を削除します。ほとんどのサーバーには、ワーカースレッドプール(W)のサイズを設定するプロパティもあります。サーバーへのW接続がすでにある場合、新しい接続が試行されるとハングする可能性があります。次に、明示的に接続を閉じるオプションがないことを想像してみてください。そのような状況では、ワーカープールが完全に使用されることがないようにタイムアウトを十分に小さく設定する必要があります。これは、同時接続数の関数です。
ただし、カーソル/接続を閉じた場合(上記の[3]で同等ではない場合でも、それらは同様に動作します)、これらのサーバー構成プロパティを管理する必要はなく、スレッドプールは単純に大きくする必要があります。すべての同時接続を管理するのに十分です(新しいリソースをときどき待機するオプションがあります)。一部のサーバー(CassandraのTitanなど)で、スレッドプールのワーカーが不足して回復できないため、サーバー全体が再起動するまで停止します。
TL/DRdano
で言及されているライブラリなど、非常によく開発されたライブラリを使用している場合は、問題は発生しません。より少ない初期のライブラリーを使用している場合、サーバーの構成とアクセス率によっては、.close()
を呼び出さないと、サーバーでワーカースレッドを取得できなくなる可能性があります。
Djangoのcursor
クラスは、基盤となるDBのcursor
のラッパーにすぎないため、cursor
を開いたままにした場合の影響は、基本的には基盤となるDBドライバーに関連付けられます。
Psycopg2's(psycopg2 is DB driver Django Uses for PostgreSQL DB's) [〜#〜] faq [〜#〜] によると、カーソルは軽量ですが、データをキャッシュしますカーソルオブジェクトを使用して行ったクエリから返された、メモリを浪費する可能性があります。
カーソルは軽量のオブジェクトであり、それらの多くを作成することは、いかなる種類の問題も引き起こすべきではありません。ただし、結果セットのフェッチに使用されるカーソルはデータをキャッシュし、結果セットのサイズに比例してメモリを使用することに注意してください。私たちの提案は、ほとんどの場合、新しいカーソルを作成し、データが不要になったらすぐに古いカーソルを破棄することです(それらに対してclose()を呼び出します)。 INSERTまたはUPDATE。
Djangoは、MySQLのバックエンドとしてMySQLdb
を使用します。これには、いくつかの異なるタイプのカーソルがあり、その中には実際に結果セットをサーバー側に格納するものもあります。 Cursor.close
の MySQLdb
ドキュメンテーション)= 使い終わったら、サーバー側カーソルを閉じることが非常に重要であることに注意してください。
サーバー側カーソルを使用している場合は、カーソルを使い終わったら、新しいカーソルを作成する前に、カーソルを閉じることが非常に重要です。
ただし、クライアント側で結果を保存するCursor
によって提供されるデフォルトのMySQLdb
クラスを使用するため、これはDjangoには関係ありません。使用済みのカーソルを開いたままにしておくと、psycopg2
と同じように、保存された結果セットが使用するメモリを浪費するおそれがあります。カーソルの close
method は、db接続への内部参照を削除し、格納された結果セットを使い果たします。
def close(self):
"""Close the cursor. No further queries will be possible."""
if not self.connection: return
while self.nextset(): pass
self.connection = None
ソースを見るとわかるように、Django( cx_Oracle 、 sqlite3 / pysqlite2 )が使用する残りのバックエンドはすべて、同じパターン;保存された結果/オブジェクト参照を削除/リセットすることでメモリを解放します。 sqlite3 docsCursor
クラスにのcloseメソッドがあることさえ言及していません。コード例。
cursor
オブジェクトで__del__()
が呼び出されると、cursor
が閉じられることは正しいので、明示的に閉じる必要があるのは、cursor
への長期にわたる参照を保持している場合のみです。例えばクラスのインスタンスメソッドとして保持しているself.cursor
オブジェクト。
cursor.close()
の明示的な呼び出しには、次の2つの理由が考えられます。
__del__
の呼び出しは保証されておらず、 here および here で読み取ることができる問題があります。この質問には少し遅れます。たぶん、exit-on-exit-scopeが必要です。
from contextlib import closing
from Django.db import connection
with closing(connection.cursor()) as cursor:
cursor.execute(...)
cursor.execute(...)
cursor.execute(...)
通常、オペレーティングシステムはリソースの解放に依存できますが、データベース接続などを閉じて、リソースが不要になったときに確実に解放されるようにすることは常に良い衛生状態です。データベースの観点からの本当に重要なことは、変更がcommit()
ed。