18

java6/hibernate/c3p0/postgresql スタックを実行しています。JDBC ドライバーは 8.4-701.jdbc3 です。

プリペアド ステートメントについていくつか質問があります。プリペアド ステートメントに関する優れたドキュメントを読みました

しかし、postgresql で c3p0 を構成する方法についてはまだ疑問があります。

現時点では

 c3p0.maxStatements = 0
 c3p0.maxStatementsPerConnection  =   0

私の理解では、準備されたステートメントとステートメントプーリングは2つの異なるものです。

私たちの休止状態スタックは準備済みステートメントを使用します。Postgresql は実行計画をキャッシュしています。次に同じステートメントが使用されると、postgresql は実行計画を再利用します。これにより、DB 内でステートメントを計画する時間が節約されます。

さらに、c3p0 は「java.sql.PreparedStatement」の Java インスタンスをキャッシュできます。これは、Java オブジェクトをキャッシュしていることを意味します。したがって、
c3p0.maxStatementsPerConnection = 100 を使用すると、最大 100 個の異なる
オブジェクトがキャッシュされます。オブジェクトを作成する時間を節約できますが、これは postgresql データベースとその準備済みステートメントとは関係ありません。

右?

約 100 の異なるステートメントを使用するため、c3p0.maxStatementsPerConnection = 100 を設定します。

しかし、c3p0 のドキュメントには、c3p0 の既知の欠点があると書かれています

ステートメント プーリングのオーバーヘッドが高すぎます。PreparedStatements の重要な前処理を実行しないドライバーの場合、プーリングのオーバーヘッドは節約を上回ります。そのため、ステートメント プーリングはデフォルトでオフになっています。ドライバーが PreparedStatements を前処理する場合、特に RDBMS を使用して IPC を介して行う場合は、Statement プールをオンにすることでパフォーマンスが大幅に向上する可能性があります。(これを行うには、構成プロパティ maxStatements または maxStatementsPerConnection をゼ​​ロより大きい値に設定します)。

c3p0 と Postgresql で maxStatementsPerConnection を有効にするのは合理的ですか? それをアクティブにする本当の利点はありますか?

よろしくジャニング

4

2 に答える 2

26

Hibernate が実際に PreparedStatement インスタンス自体を格納するのか、それとも接続プロバイダーに依存して再利用するのかは覚えていません。(BatcherImpl の簡単なスキャンは、同じ SQL を連続して複数回実行する場合、最後の PreparedStatement を再利用することを示唆しています)

c3p0 のドキュメントが作成しようとしているポイントは、多くの JDBC ドライバーにとって、PreparedStatement は役に立たないということだと思います。一部のドライバーは、クライアント側でパラメーターを単純につなぎ合わせてから、とにかく構築された SQL ステートメントをデータベースに渡します。 . これらのドライバーにとって、PreparedStatements はまったく利点がなく、それらを再利用する努力は無駄になります。( Postgresql JDBC FAQによると、これはサーバー プロトコル バージョン 3 より前の Postgresql の場合であり、ドキュメントにはより詳細な情報があります)。

PreparedStatement を有効に処理するドライバーの場合でも、PreparedStatement インスタンスを実際に再利用してメリットを得る必要がある可能性があります。たとえば、ドライバーが以下を実装する場合:

  • Connection.prepareStatement(sql) - サーバー側のステートメントを作成する
  • PreparedStatement.execute(..) など - そのサーバー側ステートメントを実行します
  • PreparedStatement.close() - サーバー側ステートメントの割り当てを解除します

これを考えると、アプリケーションが常にプリペアド ステートメントを開き、それを 1 回実行してから再度閉じる場合、何のメリットもありません。実際には、往復回数が増える可能性があるため、さらに悪化する可能性があります。したがって、アプリケーションは PreparedStatement インスタンスを保持する必要があります。もちろん、これは別の問題につながります。アプリケーションがハングアップしすぎて、サーバー側の各ステートメントがリソースを消費すると、サーバー側の問題が発生する可能性があります。誰かが JDBC を直接使用している場合、これは適切な方法で管理される可能性があります。いくつかのステートメントは再利用可能であることがわかっているため、準備されています。一部はそうではなく、代わりに一時的な Statement インスタンスを使用するだけです。(これは、準備されたステートメントの他の利点をスキップしています: 引数のエスケープの処理)

これが、c3p0 やその他の接続プールにもステートメント キャッシュが用意されている理由です。これにより、アプリケーション コードはこれらすべての処理を回避できます。通常、ステートメントは限定された LRU プールに保持されるため、一般的なステートメントは PreparedStatement インスタンスを再利用します。

パズルの最後のピースは、JDBC ドライバー自身が賢いと判断してこれを行う可能性があるということです。また、サーバー自体も巧妙であると判断し、以前のステートメントと構造的に類似したステートメントを送信するクライアントを検出する場合があります。

Hibernate 自体が PreparedStatement インスタンスのキャッシュを保持していないことを考えると、c3p0 でそれらの利点を得るにはキャッシュを保持する必要があります。(キャッシュされたプランを再利用するため、一般的なステートメントのオーバーヘッドが削減されるはずです)。c3p0 が準備されたステートメントをキャッシュしない場合、ドライバーは、アプリケーションがステートメントを準備し、実行し、再び閉じるのを見るだけです。JDBC ドライバーには、アプリケーションが常にこれを行う場合に準備/実行サーバーのオーバーヘッドを回避するための「しきい値」設定があるようです。したがって、はい、c3p0 でステートメント キャッシュを実行する必要があります。

少し長くなってすみません。答えはイエスです。

于 2010-05-27T13:07:21.707 に答える
2

接続ごとにステートメントをキャッシュする必要があることに注意してください。これは、かなりの量のメモリを消費する必要があり、効果が現れるまでに長い時間がかかることを意味します。したがって、キャッシュに 100 ステートメントを使用するように設定すると、実際には 100*接続数、または 100/接続数になりますが、キャッシュが意味のある効果を発揮するまでにはかなりの時間が必要です。

于 2010-06-23T10:12:32.580 に答える