2015-09-25 57 views
2

根據JDBC規範,該Statement.setMaxRows(int maxRows)方法應該是:如何做一個JDBC驅動程序實現setMaxRows方法

設置將此Statement對象生成的所有ResultSet 對象的最大行數限制可以包含給定的 號碼。如果超出限制,則多餘的行將自動丟棄 。

當針對限制SQL級別(ROWSET,TOP和LIMIT)的結果集進行測試時,JDBC和SQL構造似乎表現非常好。

即使在選擇數百萬行時,setMaxRows似乎並沒有表現得更差。

難道這是因爲數據庫Executor可能會使用數據庫遊標,它只需要獲取記錄,所以當驅動程序達到閾值maxRows時,可以指示數據庫關閉遊標?

這樣,數據庫不必選擇一個巨大的結果集並將其發送到電線,僅在客戶端丟棄。

回答

4

在PostgreSQL中,PgJDBC在協議級別發送一個請求,該請求相當於將LIMIT附加到查詢中。所以數據庫服務器知道盡量減少它儘可能做的工作量。例如,它可能會選擇一個計劃來獲取所有行會更加昂貴,但可以更快地開始返回一些行或避免一個大的全行排序。

我期望其他引擎的客戶端驅動程序是相似的 - 在幕後設置一個限制,或使用遊標並閱讀,直到它們有足夠的結果。

每個DBMS和驅動程序都會有所不同,因此一個明確的答案可能很難找到。

1

大多數JDBC驅動程序將按需獲取行(基於獲取大小),因此通常maxRows將非常高效。他們通常甚至優化,只能獲取不超過maxRows

A ROWSTOP可能會爲數據庫服務器提供一些額外的提示以優化查詢,因此設置maxRows可能不如在查詢本身中包含最大值。確切的行爲是依賴於驅動程序和數據庫的,因此很難概括行爲和性能特徵。

值得注意的例外是MySQL驅動程序(可能也MariaDB的),默認爲獲取所有行(除非獲取大小設置爲Integer.MIN_VALUE)立即執行查詢。

如Jaybird(火鳥JDBC驅動程序)的示例中,following完成(用於TYPE_FORWARD_ONLY):

public void fetch() throws SQLException { 
    synchronized (syncProvider.getSynchronizationObject()) { 
     checkClosed(); 
     int maxRows = 0; 

     if (this.maxRows != 0) maxRows = this.maxRows - rowNum; 

     int fetchSize = this.fetchSize; 
     if (fetchSize == 0) fetchSize = MAX_FETCH_ROWS; 

     if (maxRows != 0 && fetchSize > maxRows) fetchSize = maxRows; 

     if (!allRowsFetched && (rows.isEmpty() || rows.size() == rowPosition)) { 
      rows.clear(); 
      stmt.fetchRows(fetchSize); 
      rowPosition = 0; 
     } 

     if (rows.size() > rowPosition) { 
      setNextRow(rows.get(rowPosition)); 
      // help the garbage collector 
      rows.set(rowPosition, null); 
      rowPosition++; 
     } else { 
      setNextRow(null); 
     } 
    } 
} 

由於服務器可以決定發送比請求,額外的檢查是在next()由更多的行。

+0

但即使所有的行被提取,MySQL不使用類似的方法嗎?在開始通過電線發送響應之前,它是否必須獲取數據庫內存中的所有行? –

+0

默認的MySQL行爲是獲取所有行並將其緩存到客戶端,請參閱_ResultSet_:http://dev.mysql.com/doc/connector-j/en/connector-j-reference-implementation-notes.html。您可以使用流式結果集,但這具有其他含義,因爲在所有行都被提取之前,它不可能使用相同的連接來執行其他語句。我不知道MySQL協議如何工作的確切細節,但據我瞭解,只要您執行了查詢,就需要讀取查詢生成的所有行;但我不是100%確定的。 –

+0

根據文檔,這是它應該如何工作的,但是它必須對不限制結果集的查詢執行同樣的操作。在實踐中,性能更接近於使用LIMIT。所以,我想他們會做一些事情來優化它。 –

1

Oracle使用生產者 - 消費者設計模式。所以這些行是在客戶機開始從光標讀取到ResultSet中時生成的。有兩個優化器目標:ALL_ROWS和FIRST_ROWS(或FIRST_ROWS(n))。當使用first_rows優化器目標時,Oracle傾向於使用比hash_joins更多的嵌套循環,因此它應該以更快的速度返回第一批結果數據。但是我不確定使用setMaxRows方法是否也改變了查詢的優化器目標。