web-dev-qa-db-ja.com

Pythonのデータベース接続プーリングの最適なソリューションは何ですか?

私は、プロジェクトの非常に特殊な要件を満たすために、DAOに似たカスタムクラスをいくつか開発しました。これは、いかなる種類のフレームワーク内でも実行されないサーバー側プロセスです。

このソリューションはうまく機能しますが、新しいリクエストが行われるたびに、MySQLdb.connectを介して新しい接続を開く点が異なります。

これをPythonで接続プーリングを使用するように切り替えるための最良の「ドロップイン」ソリューションは何ですか? Java用のコモンズDBCPソリューションのようなものを想像しています。

プロセスは長時間実行され、リクエストを行う必要がある多くのスレッドがありますが、同時にすべてではありません...特に、結果のチャンクを短時間書き出す前に、かなり多くの作業を行います。

追加のために編集:少し検索した後、私は anitpool.py を見つけましたが、それはpythonに比較的新しいので、私はより明白な/より慣用的/より良い解決策を見逃していません。

32
John

IMO、「より明白な/より慣用的/より良いソリューション」は、DAOのようなクラスを発明するのではなく、既存のORMを使用することです。

ORMは「生の」SQL接続よりも人気があるようです。どうして?なぜならPythonisOOであり、SQL行からオブジェクトへのマッピング isは絶対に不可欠です。PythonオブジェクトにマップされないSQL行を処理するケースは多くありません。

SQLAlchemy または SQLObject (および関連する接続プール)は、より慣用的なPythonicソリューションだと思います。

純粋なSQL(オブジェクトマッピングなし)は、接続プーリングの恩恵を受ける複雑で長時間実行されるプロセスにはあまり人気がないため、個別の機能としてのプーリングはあまり一般的ではありません。はい、純粋なSQLが使用されますが、プーリングが役に立たない、より単純な、またはより制御されたアプリケーションで常に使用されます。

私はあなたが2つの選択肢を持っていると思います:

  1. SQLAlchemyまたはSQLObjectを使用するようにクラスを修正します。これは最初は苦痛に見えますが(すべての作業が無駄になりました)、すべての設計と思考を活用できるはずです。これは、広く使用されているORMとプーリングソリューションを採用するための練習にすぎません。
  2. 概説したアルゴリズムを使用して、独自の単純な接続プールをロールします。これは、循環する単純な接続のセットまたはリストです。
16
S.Lott

MySQLでは?

接続プールを気にしないでください。多くの場合、これらは問題の原因であり、MySQLを使用すると、期待するパフォーマンス上の利点が得られません。この領域では、接続プーリングの利点について、多くのベストプラクティスが手を振ったり、教科書の言葉遣いが行われたりするため、この道をたどるには多くの努力が必要です。

接続プールは、ステートレスアプリケーション(HTTPプロトコルなど)のWeb後の時代と、ステートフルで長期間存続するバッチ処理アプリケーションのWeb前の時代との間の単なる橋渡しです。接続前のデータベースでは接続に非常にコストがかかるため(接続の確立にどれだけ時間がかかるかを気にする必要がなかったため)、Web後のアプリケーションはこの接続プールスキームを考案し、すべてのヒットでこの大きな処理オーバーヘッドが発生しないようにしましたRDBMSで。

MySQLはよりWeb時代のRDBMSであるため、接続は非常に軽量で高速です。 MySQLで接続プールをまったく使用しない大量のWebアプリケーションを多数作成しました。

これは、克服しなければならない政治的障害がない限り、あなたがなしで利益を得ることができる合併症です。

21
mbac32768

接続クラスをラップします。

作成する接続数に制限を設定します。未使用の接続を返します。接続を解放するために閉じるを傍受します。

更新:私はこのようなものをdbpool.pyに入れます:

import sqlalchemy.pool as pool
import MySQLdb as mysql
mysql = pool.manage(mysql)
16
Chris

古いスレッドですが、汎用プーリング(接続または高価なオブジェクト)の場合、次のようなものを使用します。

def pool(ctor, limit=None):
    local_pool = multiprocessing.Queue()
    n = multiprocesing.Value('i', 0)
    @contextlib.contextmanager
    def pooled(ctor=ctor, lpool=local_pool, n=n):
        # block iff at limit
        try: i = lpool.get(limit and n.value >= limit)
        except multiprocessing.queues.Empty:
            n.value += 1
            i = ctor()
        yield i
        lpool.put(i)
    return pooled

どれが遅延して構築され、オプションの制限があり、私が考えることができるすべてのユースケースに一般化する必要があります。もちろん、これは、リソースのプールが本当に必要であることを前提としています。これは、多くの最新のSQLライクでは必要ない場合があります。使用法:

# in main:
my_pool = pool(lambda: do_something())
# in thread:
with my_pool() as my_obj:
    my_obj.do_something()

これは、必要に応じて、任意のオブジェクトカクターが作成するオブジェクトコンストラクターに適切なデストラクタがあることを前提としています(一部のサーバーは、明示的に閉じられない限り、接続オブジェクトを強制終了しません)。

6
metaperture

私はちょうど同じようなものを探していました。

pysqlpoolsqlalchemyプールモジュール が見つかりました

2
Willie

アプリがマルチスレッドの使用を開始することを決定した場合、独自の接続プールを作成することは悪い考えです。マルチスレッドアプリケーション用の接続プールの作成は、シングルスレッドアプリケーション用の接続プールよりもはるかに複雑です。その場合はPySQLPoolのようなものを使用できます。

パフォーマンスを求めている場合は、ORMを使用するのも悪い考えです。

多数の選択、挿入、更新、削除を同時に処理する必要がある巨大なデータベースを処理する場合は、パフォーマンスが必要になります。つまり、ルックアップを最適化するためにカスタムSQLを作成する必要があります。とロック時間。 ORMでは、通常、そのような柔軟性はありません。

つまり、基本的に、そうです。独自の接続プールを作成してORMを使用できますが、ここで説明した内容がまったく必要ないことが確実な場合に限ります。

2
flexo

古いスレッドに返信しますが、前回チェックしたとき、MySQLはそのドライバの一部として接続プーリングを提供しています。

あなたはそれらをチェックアウトすることができます:

https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html

TFAから、(OPが述べたように)接続プールを明示的に開きたいと仮定します。

dbconfig = {  "database": "test", "user":"joe" }
cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name = "mypool",pool_size = 3, **dbconfig)

このプールは、get_connection()関数を介してプールから要求することによりアクセスされます。

cnx1 = cnxpool.get_connection()
cnx2 = cnxpool.get_connection()
1
kilokahn

DBUtilsを使用してください。シンプルで信頼できます。

pip install DBUtils
0
ospider