web-dev-qa-db-ja.com

PreparedStatementsとパフォーマンス

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

Javaアプリケーションでは、「PreparedStatement」を使用するよりも通常の「Statement」を使用しています。PreparedStatementをさらに使用するように努めている間、私はより完全な理解を得ようとしていますクライアント側とサーバー側での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はまだキャッシュされており、私が知らないカバーの下で再利用されていますか?

また、いくつかのデータベースをサポートしていることにも触れておきます。

前もって感謝します。

53
Kapsh

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

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

したがって、準備済みステートメントを使用する理由として、SQLインジェクション攻撃に対する保護ははるかに重要ですパフォーマンスの向上です。 SQLインジェクション攻撃を心配していない場合は、おそらく...

30
Neil Coffey

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

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インジェクションを防ぐ必要があります。私の会社ではこれはインタビューの質問です。それを間違えれば私達はあなたを雇わないかもしれません。

準備されたステートメントは実際に最初の使用後にキャッシュされます。これは、標準のステートメントよりもパフォーマンスが優れているということです。ステートメントが変更されない場合は、このメソッドを使用することをお勧めします。これらは通常、変更使用のためにステートメントキャッシュ内に格納されます。

詳細はここにあります:

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

また、JDBCを直接使用する代わりに、Spring JDBCTemplateを検討することもできます。

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

14
Jon

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

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

8
duffymo

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

性能面でお答えします。ここの他の人々は、PreparedStatementsがSQLインジェクションに対して回復力があることをすでに規定しています(祝福された利点)。

アプリケーション(JDBCドライバー)はPreparedStatementを作成し、プレースホルダー(?)。 RDBMSはプリコンパイルされ、受信したPreparedStatementのクエリ最適化(必要な場合)を適用し、(一部の場合は)一般にそれらをキャッシュします。 PreparedStatementの実行中に、プリコンパイルされたPreparedStatementが使用され、各プレースホルダーが関連する値に置き換えられて計算されます。これは、コンパイルして直接実行するStatementとは対照的です。PreparedStatementはクエリをコンパイルして最適化します1回のみ。さて、上記で説明したこのシナリオは、すべてのJDBCベンダーによる絶対的なケースではありませんが、基本的にはPreparedStatementの使用方法と操作方法です。

4
Buhake Sindi

事例として:数年前にODBC in Java 1.4を使用して、OracleとSQL Serverの両方のバックエンドで、準備済みステートメントと動的ステートメントを使用して実験を行いました。Iは、準備されたステートメントが特定のクエリに対して最大20%高速になる可能性があることを発見しましたが、どのクエリがどの程度改善されたかに関してベンダー固有の違いがありました(これは実際には驚くべきことではありません)。

結論として、同じクエリを繰り返し再利用する場合、準備されたステートメントがパフォーマンスの向上に役立つ可能性があります。ただし、パフォーマンスが不十分ですぐに何かをする必要がある場合は、準備されたステートメントを使用して大幅な向上を期待しないでください。 (通常、20%は家に書くものではありません。)

もちろん、走行距離は異なります。

3
Dan Breslau

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

はい、少なくともOracleでは。 Oracle®Database JDBC開発者ガイドごと 暗黙の文キャッシュ (強調を追加)、

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

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

3
Elliott Frisch

1。 PreparedStatementを使用すると、動的でパラメトリックなクエリを作成できます

JavaでPreparedStatementを使用することにより、パラメーター化されたSQLクエリを作成し、同じSQLクエリを使用して異なるパラメーターを送信できます。これは、異なるクエリを作成するよりもはるかに優れています。

2。 PreparedStatementはJavaのステートメントよりも高速です

PreparedStatementを使用する主な利点の1つは、パフォーマンスの向上です。 PreparedStatementはデータベースで事前にコンパイルされ、アクセスプランもデータベースにキャッシュされます。これにより、データベースは準備されたステートメントを使用して記述されたパラメトリッククエリを実行することができます。データベースの負荷を軽減するために、プロダクションJDBCコードでは常にPreparedStatementを使用するようにしてください。パフォーマンス上の利点を得るには、パラメーター化されたバージョンのSQLクエリのみを使用し、文字列の連結は使用しないことが重要です。

3。 PreparedStatementはJavaのSQLインジェクション攻撃を防止します

続きを読む: http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-Java-jdbc.html#ixzz3LejuMnVL

2
Siva Kumar

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

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

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

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

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

1
Nicola Ferraro

短い答え:

通常、DBクライアントは同じクエリを繰り返し実行するため、PreparedStatementはパフォーマンスに役立ちます。これにより、最初のクエリの前処理実行して速度を上げることができます。次の反復クエリ

長い答え:

Wikipedia によると、準備済みステートメントを使用する一般的なワークフローは次のとおりです。

Prepare:ステートメントテンプレートはアプリケーションによって作成され、データベース管理システム(DBMS)に送信されます。パラメータ、プレースホルダ、またはバインド変数と呼ばれる特定の値は未指定のままになります(以下の「?」というラベルが付いています)。INSERT INTO PRODUCT(名前、価格)VALUES(?、?)

(プリコンパイル):DBMSはステートメントテンプレートを解析、コンパイル、およびクエリ最適化を実行し、実行せずに結果を保存します。

Execute:後で、アプリケーションがパラメーターの値を提供(またはバインド)し、DBMSがステートメントを実行します(結果を返す可能性があります)。アプリケーションは、ステートメントを異なる値で何回でも実行できます。この例では、最初のパラメーターに「パン」、2番目のパラメーターに「1.00」を指定します。

準備:

JDBCでは、「準備」ステップはJava.sql.Connection . prepareStatement (String sql)APIを呼び出すことによって行われます。そのJavadocによると:

このメソッドは、プリコンパイルの恩恵を受けるパラメトリックSQLステートメントを処理するために最適化されています。ドライバーがプリコンパイルをサポートしている場合、メソッドprepareStatementはプリコンパイルのためにデータベースにステートメントを送信します。一部のドライバはプリコンパイルをサポートしていない場合があります。この場合、PreparedStatementオブジェクトが実行されるまで、ステートメントはデータベースに送信されない可能性があります。これはユーザーに直接影響を与えません。ただし、特定のSQLExceptionオブジェクトをスローするメソッドには影響します。

このAPIを呼び出すと、SQLステートメントがデータベースに送信される可能性があるため、通常は高コストの呼び出しです。 JDBCドライバーの実装によっては、同じSQLステートメントテンプレートを使用している場合、パフォーマンスを向上させるために、同じSQLステートメントテンプレートに対してクライアント側でこのAPIを何度も呼び出さないようにする必要があります。

プリコンパイル:

送信されたステートメントテンプレートは、データベースで事前コンパイルされ、dbサーバーにキャッシュされます。データベースはおそらく、接続とSQLステートメントテンプレートをキーとして使用し、プリコンパイルされたクエリと計算されたクエリプランをキャッシュ内の値として使用します。クエリの解析では、テーブルとクエリ対象の列を検証する必要がある場合があるため、コストのかかる操作になる可能性があり、 クエリプラン の計算もコストのかかる操作です。

実行:

同じ接続とSQLステートメントテンプレートからの次のクエリの場合、事前にコンパイルされたクエリとクエリプランは、再計算せずにデータベースサーバーによってキャッシュから直接検索されます。

結論:

パフォーマンスの観点から、prepareステートメントの使用は2段階のプロセスです。

  1. フェーズ1、準備およびプリコンパイル。このフェーズは1回実行され、パフォーマンスのオーバーヘッドを追加すると予想されます。
  2. フェーズ2、同じクエリの繰り返し実行、フェーズ1にはクエリの前処理があるため、繰り返しクエリの数が十分に多い場合、これにより、同じクエリの多くの前処理作業を節約できます。

さらに詳細を知りたい場合は、PrepareStatementの利点を説明する記事がいくつかあります。

  1. http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-Java-jdbc.html
  2. http://docs.Oracle.com/javase/tutorial/jdbc/basics/prepared.html
1
nybon