2017-02-21 11 views
5

は私がresultSet.next():バッファORからデータベースからデータをフェッチしますか?

のステートメントフェッチサイズは10000ですstatement.executeQuery()が実行されたとき、それは、ResultSetのカーソルを返し、次のように

try (Connection connection = this.getDataSource().getConnection(); 
     PreparedStatement statement = connection.prepareStatement(sqlQuery);) { 


     try { 
      statement.setFetchSize(10000); // Set fetch size 
      resultSet = statement.executeQuery(); 

      while (true) { 
       resultSet.setFetchSize(10000); 
       boolean more = resultSet.next(); 
       if (! more) { 
        break; 
       } 
       // populating an arraylist from the value from resultSet 
      } 
     } 
     catch (Exception e) { 
      LOGGER.error("Exception : "+e); 
     } 
    } catch (SQLException e) { 
     LOGGER.error("Exception : "+e); 
    } 

私の理解では、以下のようなコードを持っています。メモリには10000行あります。 resultSet.nextが呼び出されると、メモリバッファから1行が取得されます。 (コールごとに1行)。メモリ内に行がなくなると、クエリが再度実行され、データベースから再度10000行がフェッチされ、バッファに格納されます。私の理解が正しければこれはDB

からフェッチする行が存在しなくなるまで続けますので、DBはを呼び出しますどのように多くの実際のは210000の合計行のためにそこになりますか?それは21ですか? (210000/10000)

また、(バッファの行がすべて読み込まれているとき)DBを呼び出して、より多くの行(私の場合は10000)を取得し、バッファに格納するとき。バッファーはいつクリアされますか?

私の理解が間違っている場合は、私に修正してください。

Oracle Databaseでは、何百万というデータを扱う必要があります。あなたのご質問にはお答えすることができます任意のポインタ/情報

よろしくため

おかげで、

SD

+0

'setFetchSize#'メソッドはヒントになっています。 JDBCドライバを使用するか無視するかは、JDBCドライバに完全に依存しています。また、 '誰がDBを呼び出しますか? ' - >ドライバがそれを行います。この[SO Q/A](http://stackoverflow.com/questions/1318354/what-does-statement-setfetchsizensize-method-really-do-in-sql-server-jdbc-driv)からそのほとんどを得ました –

+0

OCIドライバの場合、各OCIコールごとのネットワーク・ラウンドトリップの量を記述するセクションがドキュメントにあります。 JDBCドライバーは、この方法では文書化されていません。より高レベルのAPIを提供します。ただし、OCIドキュメントをトピックの紹介として使用できます。 – ibre5041

答えて

3

だけの人では、Oracle JDBCドライバの作者です。

次のデータのチャンクを読み込むためのdbの呼び出しには、数ms(またはそれ以下)時間がかかりませんが、大部分の時間は転送速度に依存します。結果セットから。

コールごとに数百レコードを上回ると、より大きなフェッチサイズを設定するリターンが小さくなると思います。

結果セットへの参照が緩くなれば、バッファーを消去することについては、ガベージコレクションドメインが主になります。

パフォーマンスの理由とメモリフットプリントの両方について、あなたのステートメントがFORWARD ONLYであることを確認してください。

connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);

+0

有用なリンク:[Oracle JDBC Documentation](https://docs.oracle.com/cd/E11882_01/java.112/e16548/resltset.htm#JJDBC28621) – Izruo

+0

フェッチ・サイズが1Kを超えると、それほど大きな違いはありません。データベース側から何が起きているのかを確認したい場合は、SQLトレースを有効にすることができます – BobC

4

申し訳ありませんが、ご理解が間違っています。 「クエリーはもう一度起動される」というようなことはありません。

クエリの実行は1回実行されます。これは、クエリを処理するための初期の時間がかかります(クエリの最適化以外のことはできません)。その後、クライアントに転送する必要があるサーバー上に行が生成されます。行が転送されている間、サーバーはおそらく転送される行をさらに生成し続け、サーバー上にバッファリングします。このサーバーサイドのバッファリングは、このQ & Aで話している種類のバッファリングとはまったく関係がありません。 (たぶん、サーバー構成によって)ある時点で、サーバー上のすべての行が収集され、残りの行をサーバーからクライアントに転送することだけが残ります。

クライアントが知る限り、クエリがサーバーに送信されると、サーバーが考えている間に一定の遅延があります。その後、行は通常はワイヤがそれらを運ぶことができるように速く。したがって、クライアントはresultSet.next()でこれらの行の読み取りを開始します。

resultSet.next()を呼び出すたびに、クライアントからサーバーに要求が送信され、次の行を送信するように指示され、サーバーはその行だけで応答します。これにより、最初の行が非常に迅速に生成されますが、クライアントとサーバーの間に多すぎるラウンドトリップが発生するため、長期的には非常に非効率的になります。

バッファリングでは、最初にresultSet.next()を呼び出すと、サーバーから一連の行が要求されます。これは、最初の行を受け取る時間にペナルティを課すことになります。なぜなら、100行がワイヤを介して送信されるのを待たなければならないからですが、長期的には、ネットワークの総オーバーヘッドを大幅に削減します。 1行あたりのクライアントとサーバー間の1回のラウンドトリップです。

resultSet.setFetchSize()の理想的な戦略は、それをそのまま残しておき、あまり心配しないことです。

しかし、あなたがパフォーマンスについて狂っている場合は、最初の行をすばやく取得するためにかなり小さいフェッチサイズ(たとえば10)から開始してから、特定の最大値(たとえば100)を超えても、実際には改善はありません。

+0

最後の段落は、処理中に開いているResultSetのフェッチサイズを変更できることを示唆しているようです。それはあなたが意味することですか? –

+0

@GordThompsonまあ、それは私が言ったことです。私はOPがそれを使用しているときにそれが失敗していないので、それが動作すると仮定します。もちろん私は間違っているかもしれません。私はそれがRDBMSの実装に依存していると仮定しますが、私は標準を見ていません。しかし何かはあなたの質問は修辞的であると私に言います。なぜあなたは知っていることを述べていないのですか?その最後の段落を修正することができますか? –

+0

@GordThompson開いているカーソルのフェッチサイズを変更することはできます。 JDBCドライバがそれをサポートしているかどうかにかかわらず、実装はそれを無視します。 –

関連する問題