57

そのため、PreparedStatementsはパフォーマンスに優れていると聞き続けています。

「PreparedStatement」よりも通常の「Statement」を使用するJavaアプリケーションがあります。より多くのPreparedStatementsを使用する方向に進んでいる間、私は、PreparedStatementsがクライアント側とサーバー側でどのように機能するかをより完全に理解しようとしています。

それで、いくつかの典型的なCRUD操作があり、アプリケーションでオブジェクトを繰り返し更新する場合、PSを使用するのに役立ちますか?毎回PSを閉じる必要があることを理解しています。そうしないと、カーソルリークが発生します。

では、パフォーマンスにどのように役立ちますか?ドライバはプリコンパイルされたステートメントをキャッシュし、次にconnection.prepareStatementを実行するときにコピーを提供しますか?または、DBサーバーは役に立ちますか?

PreparedStatementsのセキュリティ上の利点についての議論を理解し、それを強調する以下の回答に感謝します。ただし、PreparedStatementsのパフォーマンス上の利点に焦点を当ててこの議論を続けたいと思います。

更新:データの更新と言うとき、私は実際には、そのメソッドがランダムに数回呼び出されるという意味でより多くのことを意味します。ループ内でステートメントを再利用するように求める以下の回答の利点を​​理解しています。

    // some code blah blah
    update();

    // some more code blah blah 
    update();

.... 

public void update () throws SQLException{
 try{
      PreparedStatement ps = connection.prepareStatement("some sql");
      ps.setString(1, "foobar1");
      ps.setString(2, "foobar2");
      ps.execute();
 }finally {
     ps.close();

 }

}

'ps' javaオブジェクトを実際に再利用する方法はなく、実際のconnection.prepareStatement呼び出しは非常にコストがかかることを理解しています。

それが私を元の質問に戻すものです。この「いくつかのSQL」PreparedStatementは、私が知らないカバーの下でまだキャッシュされ、再利用されていますか?

また、いくつかのデータベースをサポートしていることにも言及する必要があります。

前もって感謝します。

4

10 に答える 10

34

準備されたステートメントが主にパフォーマンスに関するものであるという考えは、か​​なり一般的なものですが、誤解のようなものです。

別の投稿者は、Oracle と SQL Server で速度が約 20% 向上したことに言及しました。MySQL で同様の図を確認しました。クエリの解析は、関係する作業の重要な部分ではないことがわかりました。非常にビジーなデータベース システムでは、クエリの解析が全体的なスループットに影響を与えるかどうかも明らかではありません。全体として、データがディスクから戻ってくる間アイドル状態になる CPU 時間を使い果たしている可能性があります。

したがって、プリペアド ステートメントを使用する理由として、 SQL インジェクション攻撃に対する保護は、パフォーマンスの向上よりもはるかに重要です。そして、SQL インジェクション攻撃を心配していないのであれば、おそらく心配すべきでしょう...

于 2009-03-26T21:49:58.987 に答える
29

準備されたステートメントは、準備した同じステートメントを再利用するときにパフォーマンスを向上させることができます。

PreparedStatement ps = connection.prepare("SOME SQL");

for (Data data : dataList) {
  ps.setInt(1, data.getId());
  ps.setString(2, data.getValue();
  ps.executeUpdate();
}

ps.close();

これは、ループ内でステートメントを作成するよりもはるかに高速です。

一部のプラットフォームでは、準備済みステートメントもキャッシュされるため、それらを閉じても、より迅速に再構築できます。

ただし、パフォーマンスが同じであったとしても、準備済みステートメントを使用して SQL インジェクションを防ぐ必要があります。私の会社では、これは面接の質問です。間違えると、あなたを雇わないかもしれません。

于 2009-03-26T21:30:39.157 に答える
18

プリペアドステートメントは、実際に最初の使用後にキャッシュされます。これは、標準のステートメントよりもパフォーマンスが向上します。ステートメントが変更されない場合は、この方法を使用することをお勧めします。これらは通常、変更用にステートメントキャッシュ内に保存されます。

詳細については、こちらをご覧ください。

http://www.theserverside.com/tt/articles/article.tss?l=Prepared-Statments

また、JDBCを直接使用する代わりに、SpringJDBCTemplateを検討することをお勧めします。

http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html

于 2009-03-26T21:26:00.400 に答える
8

SQL の解析だけが行われているわけではありません。テーブルと列が実際に存在することの検証、クエリ プランの作成などがあります。PreparedStatement で 1 回支払います。

実際、SQL インジェクションを防ぐためのバインドは非常に優れています。十分ではありません、IMO。永続化レイヤーに到達する前に、入力を検証する必要があります。

于 2009-03-26T22:51:29.867 に答える
3

逸話: 私は、数年前に Oracle と SQL Server の両方のバックエンドで、Java 1.4 の ODBC を使用して、準備された文と動的な文でいくつかの実験を行いました。特定のクエリでは、プリペアド ステートメントの方が 20% も高速になる可能性があることがわかりましたが、どのクエリがどの程度改善されたかに関しては、ベンダー固有の違いがありました。(これは驚くべきことではありません。)

肝心なのは、同じクエリを繰り返し再利用する場合、準備済みステートメントがパフォーマンスの向上に役立つ可能性があるということです。しかし、パフォーマンスが非常に悪く、すぐに何かをする必要がある場合は、準備済みステートメントを使用して劇的な後押しを期待しないでください。(通常、20% は特記すべきことではありません。)

もちろん、走行距離は異なる場合があります。

于 2009-03-26T21:31:33.227 に答える
3

これが、元の質問に戻る理由です。この「いくつかのSQL」PreparedStatementは、私が知らないカバーの下でまだキャッシュされ、再利用されていますか?

はい、少なくとも Oracle では。Oracle® Database JDBC Developer's Guide Implicit Statement Caching (強調を追加) に従って、

close暗黙的な Statement キャッシングを有効にすると、JDBCは、このステートメント オブジェクトのメソッドを呼び出したときに、準備済みまたは呼び出し可能なステートメントを自動的にキャッシュします。準備された呼び出し可能なステートメントは、標準の接続オブジェクトとステートメント オブジェクト メソッドを使用してキャッシュされ、取得されます。

プレーン ステートメントは暗黙的にキャッシュされません。これは、暗黙的なステートメント キャッシュでは SQL 文字列がキーとして使用され、プレーン ステートメントは SQL 文字列なしで作成されるためです。OraclePreparedStatementしたがって、暗黙的な Statement キャッシングは、SQL 文字列で作成されたおよびOracleCallableStatementオブジェクトにのみ適用されます。OracleStatement で暗黙的な Statement キャッシングを使用することはできません。OraclePreparedStatementorを作成するOracleCallableStatementと、JDBC ドライバーはキャッシュ内で一致するステートメントを自動的に検索します

于 2014-12-08T08:12:54.213 に答える
1

プリペアド ステートメントには、使用方法に応じて、通常のステートメントに対するパフォーマンスの点でいくつかの利点があります。誰かが前に述べたように、同じクエリを異なるパラメーターで複数回実行する必要がある場合は、準備されたステートメントを再利用して、新しいパラメーター セットのみを渡すことができます。パフォーマンスの向上は、使用している特定のドライバーとデータベースによって異なります。

たとえば、データベースのパフォーマンスに関して、Oracle データベースは各計算の後に一部のクエリの実行計画をキャッシュします (これは、Oracle のすべてのバージョンおよびすべての構成に当てはまるわけではありません)。これは RDBMS レベルで行われるため、ステートメントを閉じて新しいステートメントを開く場合でも、改善を見つけることができます。この種のキャッシュは、後続の 2 つのクエリが (文字ごとに) 同じである場合にのみ有効になります。パラメータはクエリの一部であり、異なる SQL 文字列を生成するため、これは通常のステートメントには当てはまりません。

他の RDBMS の中にはもっと「インテリジェント」なものもありますが、パフォーマンスが低下するため、実行計画をキャッシュするために複雑なパターン マッチング アルゴリズムを使用することはないと思います。実行計画の計算はクエリ実行のごく一部に過ぎないと主張するかもしれません。一般的なケースについては同意しますが、場合によって異なります。通常、rdbms は (Oracle だけでなく) 統計などのオフメモリ データを参照する必要があるため、実行計画の計算は高価なタスクになる可能性があることに注意してください。

ただし、キャッシュに関する議論は、実行計画から抽出プロセスの他の部分にまで及びます。RDBMS に同じクエリを (特定の実装について詳しく説明することなく) 複数回与えると、JDBC (ドライバー) または RDBMS レベルで既に計算された構造を識別するのに役立ちます。現時点でパフォーマンスに特に利点が見られない場合でも、ドライバー/rdbms の将来/代替バージョンでパフォーマンスの改善が実装されることを除外することはできません。

バッチモードで準備済みステートメントを使用すると、更新のパフォーマンスが向上しますが、これは別の話です。

于 2014-12-11T00:51:16.667 に答える