2017-11-08 8 views
0

私はprepareStatement(String sql)の説明と、パフォーマンスとキャッシングに関連する投稿の多くをPreparedStatementと読んでいます。このデータベースは、準備されたステートメントのクエリを解析してコンパイルすることは明らかです。それ以降、同じクエリのため、別の解析のラウンドとコンパイルは発生しませんが、私はかどうかについては明らかではない午前:"prepareStatement(String sql)"の内部機能

  • prepareStatement(String sql)の各呼び出しは、データベースの呼び出しにつながるか、しないのだろうか?私はそれができると思います。
  • 呼び出すたびにprepareStatement(String sql)が呼び出されると、データベース呼び出しが発生し、docsからこの行が何を意味するのか分かりません。"INパラメータの有無にかかわらずSQL文をプリコンパイルしてPreparedStatementオブジェクトに格納できます。?私たちが得ている実際のパフォーマンスの利点はRDBMS側にあるので、PreparedStatementオブジェクトはそれで何をしていますか?
  • PreparedStatementオブジェクトを使用してクエリ(単純なSELECT、パラメータ化なし)を実行したとしたら、Statementオブジェクトを使用して同じクエリを実行すると、RDBMSは引き続き解析しコンパイルするかどうかを確認します。
+0

この質問に対する回答はおそらくベンダー固有のものです。特定のJDBCドライバについて質問していますか?もしそうなら、どちらですか? –

答えて

1
  1. はい、prepareStatementのすべての呼び出しは、データベースの呼び出しをもたらすべきです。いいえ、それは可能性がある場合は、このシナリオを言う:

    execute("create table x(y integer)"); 
    prepareStatement("select * from x"); // #1 
    execute("rename table x to old_x"); 
    execute("create table x(z varchar(100))"); 
    prepareStatement("select * from x"); // #2 - this stamenent is not equal to previous 
    
  2. PreparedStatementは、一般的にカーソル・ハンドルのラッパーです。 prepareStatementは、SQL文をRDBMSに送信します。 RDBMSはそれをコンパイルしてハンドルを返します。次のデータベース呼び出しはこのハンドルを使用するため、RDBMSはコンパイルされたステートメントを使用します。

  3. これはRDBMSによって異なります。 Oracleは、この場合、「ソフト解析」を使用します。ソフト構文解析とは、データベース内のequal文をキャッシュ内に配置し、可能であればそれを使用することを意味します。再コンパイルより効果的ですが、準備されたステートメントを使用するより効果的ではありません。

+0

お返事ありがとうございます。 「*ハンドルを返す」という意味は何ですか?詳細を教えてください。これは大きな混乱のあるところです。 – pjj

+0

この回答はすべてのJDBCドライバでは正しくありません。特に、Oracle Database JDBCドライバでは正しくありません。 –

+0

@DouglasSurberどの点が間違っているのかを教えてください。また、自分の答えを入れることができれば最高でしょう。 – pjj

2

次は、Oracle Database JDBCドライバにのみ適用されます。他のドライバは異なる場合があります。

Connection.prepareStatement(String)を呼び出すと、データベースのラウンドトリップは行われません。新しいPreparedStatementを構築し、その中にSQL文字列を格納します。それはそれです。

未使用のPreparedStatementでも適度に複雑ですので、これはまったく簡単な呼び出しではありません。それでも、未使用のPreparedStatementのキャッシュにはあまり価値がありません。新しいものを構築するコストは低いです。 「未使用」を強調する。 PreparedStatementの最初の実行は完全な往復を行い、PreparedStatementの構築を完了します。 PreparedStatementを再利用すると、新しいPrepareStatementを作成して初めて使用するコストよりはるかに少なくなります。

2つのPreparedStatementsで同じSQLを実行すると、クライアントとサーバーの両方で1つのPreparedStatementを2回実行するよりもコストがかかります。クライアントの場合、追加費用はかなり簡単です。 2番目のPreparedStatementを完全に構築するコストです。これには、クライアントが最初に実行されたラウンドトリップの後に実行する作業が含まれます。物事はデータベースでそれほど単純ではありません。

Oracle Databaseには、複数のレベルのキャッシュと再利用があり、指定されたSQL文字列を複数回実行するコストを最小限に抑えます。 PreparedStatementはカーソルIDを保持します。そのIDはサーバー内のカーソルを参照します。カーソルは、SQL実行のデータベース表現である複雑な構造です。構造体の中には、同じSQLを実行する他のカーソルと共有することができます。構造の一部は、単一の実行に固有のものです。いくつかの構造体は、SQLを実行するカーソル間で共有できますが、他の構造体は共有できません。それは複雑なシステムです。

一般に、新しいPreparedStatementを作成するには、ハード解析が必要です。サーバがその前にSQLを見た場合、サーバはカーソル構造のいくつかを再利用できるので、ハード解析は完全なハード解析ではないかもしれません。アプリケーションがPreparedStatementを再実行する場合、理想的にはサーバーはカーソルに対して何もする必要はありません。それだけでそれを再実行します。しかし、サーバが再解析を実行する前にソフト解析を行わなければならない場合が多い。ソフト解析は、ハード解析よりも機能は少なくなりますが、自明ではありません。

上記は、暗黙的な文キャッシュを無視します。暗黙の文キャッシュは、Prepared文とCallable文を実行して作成された構造体を格納します。アプリケーションがSQLを実行し、PreparedStatementを閉じた後、同じSQLを持つ新しいPreparedStatementを作成し、最初の実行によって作成された構造が再利用されます。キャッシュ内にあったPreparedStatementの最初の実行のコストは、すべての実際的な目的のために、同じPreparedStatementを再実行するのと同じです。

+0

お返事ありがとうございました。 – pjj

-1

@Sandersと@Douglasは良いですが、完全ではない(JDBCドライバのみを考慮しても)ので、私も答えは入れていません。これも完全ではありません。 :PreparedStatementの

  • PreparedStatementオブジェクトの

    パフォーマンスの利点は、動的照会に最適とSQLインジェクションの視点を回避からも優れています。 PreparedStatementので

  • キャッシュ:データベースレベルで
    1. キャッシュ:データベースレベルでのキャッシングで
      • 、あなたはPreparedStatementオブジェクトとパラメータ化クエリを使用する場合、最初の実行のためのDBサーバが解析し、コンパイルしますクエリを実行してその実行計画をキャッシュするようになりました。同じパラメータ化されたクエリが再び現れたとき、これらすべてのことを再度実行する必要はありませんので、パフォーマンス上のメリットが得られます(なぜ、パラメタ化されたクエリを使用するか、 。
      • したがって、dbサーバーは、解析、コンパイル、実行計画時刻の特定を避けるために、クエリをキャッシュできます。 J2EEサーバーレベルで
    2. キャッシュ:今
      • 、私は注意することが重要なことを開始する前に、スタンドアロンのJavaプログラムを持っているならば、あなたが得ることができない、このキャッシングは唯一のJ2EEサーバの場合にはあるということですこのキャッシング
      • JEEサーバーの場合、プールされた接続オブジェクトが取得されます。ここで準備されたステートメントオブジェクトを作成すると、JEEサーバーはそのデータベース接続用に準備されたステートメントオブジェクトをキャッシュします(ここで重要なことはJEEサーバーの場合、接続オブジェクトのcloseメソッドを呼び出すと、データベースサーバーとの実際の接続は閉じられず、プロキシ/ラッパー接続オブジェクトのみが閉じられるため、接続にいくつかのプロパティを設定していればオブジェクトの場合はまだそこにあります)、同じ接続オブジェクトがアプリケーションに返されたときに、同じクエリがプリペアドステートメントオブジェクトで使用された場合、JEEサーバーはdbサーバーへのラウンドトリップをスキップし、 。あなたはPreparedStatementを使用してクエリをコンパイルして、異なるパラメータを渡すために、このオブジェクトを使用することができますので、
  • のPreparedStatementは、パフォーマンスの観点から優れています。 Statementオブジェクトを使用してパラメータを設定または渡すことはできません。新しい文オブジェクト(dbサーバへのラウンドトリップを意味する)を作成して実行するたびにdbサーバーへの別のラウンドトリップを意味します)。ここでPreparedStatementの大文字小文字を確認したら、クエリパラメータを指定して(これはdbサーバへのラウンドトリップを意味する)PreparedStatementオブジェクトを作成し、このオブジェクトに別のパラメータを設定して実行することができます。 PreparedStatementオブジェクトを1回だけ作成します。これは、dbサーバーへの1回の往復を意味し、Statementオブジェクトの場合にそこにあったオブジェクト作成用のdbサーバーへのラウンドトリップを保存します。さて、あなたがPreparedStatementオブジェクトではなく、「+」演算子ベースの真であるクエリ、しかし、重要でパラメータ化クエリを使用するべきであると言われて
    • :「+」演算子ベースの問合せ対パラメータ化クエリを使用して
    • 注目すべき点は、パフォーマンスの改善はないとは言えません。Statementオブジェクトの代わりにPreparedStatementオブジェクトを使用するとすぐに、オブジェクト作成のためのdbサーバーへのラウンドトリップを回避することによって利益を得るので、確かに利点があります。しかし、 "+"演算子を使用することの短所はdbサーバー側であり、 "+"演算子を使用すると、dbサーバーはパラメータ化されたクエリを使用すると発生するクエリをキャッシュできません。注意すべき
  • もう一つ重要なことは、あなたはそれがstandlone Javaプログラムであれば、それはJ2EEサーバであるならば、可能性の往復にそれがある間は、サーバーへのラウンドトリップが起こる、その後connection. prepareStatement()を呼び出すときということですサーバーがJEE PreparedStatementキャッシュのために発生しない
+0

「J2EE」という用語は、数年前に「Java EE」に置き換えられ、「EE4J」という用語に置き換えられようとしています。また、あなたのセクションで "+演算子ベースのクエリ"(それが何であれ)を伝えようとしているかどうかはわかりませんが、質問には関係していないようです。 –

+0

@MarkRotteveel私は、自分の投稿は情報だけであり、すべてには答えないことを開始自体に述べました。 – pjj

+0

上記の回答のほぼすべての箇条書きに、重大なエラーが含まれています。 1)OracleConnection.prepareStatementはラウンドトリップを行いません。ステートメントでPreparedStatementを使用した往復はもうありません。非Java EEアプリケーションは、ステートメントキャッシュを持つことができます。 「Oracle Implicit Statement Cache」を参照してください。サーバーがカーソルを再利用できるときは、最初の箇条書きで説明したよりもはるかに複雑です。アプリがPreparedStatementを再利用しているだけでは、サーバが再解析しないことは保証されません。 –

関連する問題