2013-07-04 119 views
2

執行查詢後,何時PostgreSQL JDBC driver版本9.2-1002從服務器獲取行?在查詢執行後(客戶端應用程序調用PreparedStatement.executeQuery()後),還是在客戶端應用程序首次調用ResultSet.next()從結果集中檢索行之後,它是否立即獲取行?這是否取決於語句讀取大小的值?執行查詢後,PostgreSQL JDBC驅動程序何時獲取行?

+0

爲什麼你會在意嗎?或者換句話說:爲什麼有人會在那之後立即調用'executeQuery'和* not * call'next()'? –

+0

我想分開執行查詢所需的時間來獲取行並處理結果集所需的時間。查詢執行時間是否包含獲取行的時間,或者結果集處理是否包含獲取時間? –

+0

我認爲測試這個最好的方法是編寫一個簡單的程序,啓動一個調試器,添加一些斷點並通過wireshark(或類似工具)觀察流量。 –

回答

3

如以下程序所示,PreparedStatement.executeQuery()總是從服務器中檢索結果集中的行。該程序還演示了語句讀取大小如何影響行檢索。在語句的默認讀取大小爲零的情況下,executeQuery()從服務器檢索所有行,ResultSet.next()檢索並返回內存中的下一行,而不是從服務器返回。 (程序甚至可能在執行查詢後關閉連接,並且next()仍然可以遍歷所有行)。在獲取大小非零的情況下,executeQuery()將檢索第一批行,其數量等於獲取大小,而ResultSet.next()再次從內存中返回下一行,直到它消耗當前批處理中的所有行,此時它將從服務器檢索下一批行。重複此模式直到ResultSet.next()從服務器(包含零行的一個)中檢索到空批處理。

SQL

-- Create table "test" and insert 2,000,000 integers from 1 up to 2,000,000. 
WITH RECURSIVE t(n) AS 
(
    VALUES (1) 
    UNION ALL 
    SELECT n+1 
    FROM t 
    WHERE n < 2000000 
) 
SELECT n as value 
INTO test 
FROM t; 

的Java

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Statement; 
import java.util.Date; 
import java.util.Properties; 

public class Start 
{ 
    public static void main(String[] args) throws InterruptedException, SQLException 
    { 
     try 
     { 
      Class.forName("org.postgresql.Driver"); 
     } 
     catch (ClassNotFoundException e) 
     { 
      System.out.println("Where is your JDBC Driver?"); 
      e.printStackTrace(); 
      return; 
     } 

     System.out.println("Registered JDBC driver"); 
     Connection connection = null; 

     try 
     { 
      final String databaseUrl = "jdbc:postgresql://localhost:5483/postgres"; 
      final Properties properties = new Properties(); 
      connection = DriverManager.getConnection(databaseUrl, properties); 
      connection.setAutoCommit(false); 
      Statement statement = connection.createStatement(); 

      // Default fetch size of 0 does not create a cursor. 
      // Method executeQuery will retrieve all rows in result set. 
      statement.setFetchSize(0); 

      // Fetch size of 1 creates a cursor with batch size of 1. 
      // Method executeQuery will retrieve only 1 row in the result set. 
      //statement.setFetchSize(1); 

      System.out.println(new Date() + ": Before execute query"); 
      ResultSet result = 
       statement.executeQuery("select * from test"); 
      System.out.println(new Date() + ": After execute query"); 
      System.out.println(new Date() + ": Sleep for 5 s"); 
      Thread.sleep(5000); 
      System.out.println(new Date() + ": Before process result set"); 
      while (result.next()); 
      System.out.println(new Date() + ": After process result set"); 
      result.close(); 
      statement.close(); 
     } 
     catch (SQLException e) 
     { 
      System.out.println("Connection failed!"); 
      e.printStackTrace(); 
      return; 
     } 
     finally 
     { 
      if (connection != null) 
       connection.close(); 
     } 
    } 
} 
+0

您可以[在jdbc中設置fetchsize](http://webmoli.com/2009/02/01/jdbc-performance-tuning-with-optimal-fetch-size/) – hd1

2

看這個documentation

默認情況下,驅動程序收集所有的查詢結果一次。這對於大數據集可能不方便,因此JDBC驅動程序提供了在數據庫遊標上設置ResultSet的方法,並且只提取少量的行。

在連接的客戶端會緩存少量行,當耗盡時,通過重新定位遊標來檢索下一個行塊。

此外read this

通常,libpq的收集SQL命令的整個結果,並將其返回給應用程序作爲單個的PGresult。對於返回大量行的命令,這可能不可行。對於這種情況,應用程序可以在單行模式下使用PQsendQuery和PQgetResult。在這種模式下,結果行一次返回到應用程序,因爲它們是從服務器接收的。

+0

這並不能告訴我驅動程序何時從服務器獲取結果。當客戶端應用程序調用PreparedStatement時,驅動程序是否檢索結果?executeQuery()'或僅在第一次調用ResultSet.next()或其他結果集導航方法之後調用? –

+0

@DerekMahar如果您想確切知道何時,那麼您需要查看PostgreSQL JDBC驅動程序的源代碼。 –

+0

驅動程序緩存'fetchSize'數量中的請求行。每次請求超出緩存的'fetchSize'行的行數時,都會請求額外的行,直到結果集耗盡。您可以通過http://docs.oracle.com/javase/6/docs/api/java修改'fetchSize' /sql/Statement.html#setFetchSize%28int%29 – sehrope