2009-10-06 115 views
8

我正在使用JDBC(使用最新的驅動程序和UCP作爲DataSource)對Oracle 10g執行查詢以檢索CLOB(平均20k字符)。但是性能似乎相當糟糕:100個LOB的批量檢索平均需要4秒。從我的觀察結果來看,該操作既不是I/O也不是CPU,也不是網絡界限。Oracle CLOB性能

我的測試設置是這樣的:

PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource(); 
dataSource.setConnectionFactoryClassName("..."); 
dataSource.setConnectionPoolName("..."); 
dataSource.setURL("..."); 
dataSource.setUser("..."); 
dataSource.setPassword("..."); 

dataSource.setConnectionProperty("defaultRowPrefetch", "1000"); 
dataSource.setConnectionProperty("defaultLobPrefetchSize", "500000"); 

final LobHandler handler = new OracleLobHandler(); 
JdbcTemplate j = new JdbcTemplate(dataSource); 

j.query("SELECT bigClob FROM ...", 

     new RowCallbackHandler() { 

      public void processRow(final ResultSet rs) throws SQLException { 

       String result = handler.getClobAsString(rs, "bigClob"); 

      } 

     }); 

} 

我試驗了取大小,但無濟於事。難道我做錯了什麼?使用JDBC時,有什麼方法可以加速CLOB檢索?

+0

你是怎麼確定它沒有網絡綁定的?您正在討論設置新的JDBC連接(價格昂貴),2Mb的數據從磁盤讀取,通過網絡發送以及查詢開銷(未指定)。根據您的網絡佈局和數據庫設置,我不知道4s是不是很糟糕。 – Gandalf 2009-10-06 17:38:13

+0

澄清:我測量的*單位*爲100,因此連接的初始處罰不計算在內。總的網絡吞吐量保持在2Mbit/s以下,所以我認爲它不受網絡限制。 – yawn 2009-10-06 19:12:03

+0

實際查詢需要多長時間? – Gandalf 2009-10-06 20:35:52

回答

2

感謝您的所有有用的建議。儘管被標記爲解決問題的答案,但我的答案是似乎沒有好的解決方案。我嘗試使用並行語句,不同的存儲特性,預分類溫度。桌子和其他東西。該操作似乎不受通過痕跡或解釋計劃可見的任何特徵的束縛。即使查詢並行性在涉及CLOB時似乎也很粗略。

毫無疑問,在11g環境中處理大型CLOB(特別是壓縮)會有更好的選擇,但atm。我堅持10g。

我現在選擇了額外往返數據庫,我將在其中將CLOB預處理爲尺寸優化的二進制RAW。在以前的部署中,這一直是一個非常快速的選擇,並且可能會維護離線計算緩存的麻煩。緩存將被無效,並使用持續進程和AQ進行更新,直到有人提出更好的想法。

+0

看起來像一個很好的解決方法,就好像您檢索100行一樣,您將支付額外往返票,但可節省100次往返票,完全可以節省100-1 = 99次往返票。但你是如何實現它的? – user451795 2010-11-19 08:14:07

+0

通過僅提取CLOB +某些鍵以稍後識別它們並將它們寫入本地鍵值存儲區。我使用了[Oracle Berkeley DB](http://www.oracle.com/technetwork/database/berkeleydb/overview/index.html),但是您可以輕鬆使用SQLite或其他任何我想要的東西。 – yawn 2010-11-19 09:28:02

6

結果集的總大小是在一萬 - 在整個檢索的標準來衡量初始成本

有一個ORDER BY查詢?如果要排序的話,10K行相當多。

此外,檢索PK不是檢索整個CLOB的公平測試。 Oracle將塊表中的行存儲爲可能多個塊,但是每個CLOB(如果它們大於4K)都將以不連續的方式存儲,每個CLOB都包含在一系列塊中。因此掃描PK的列表將會很快。另外,PK上可能有索引,所以Oracle可以快速掃描索引塊,甚至不訪問表。

4秒看起來似乎有點高,但需要從磁盤讀取並通過網絡傳輸到您的Java程序需要2 MB。網絡可能是一個問題。如果您執行會話的SQL跟蹤,它會指向您準確使用時間的位置(磁盤讀取或網絡)。

5

我以前使用oracle LOB類型數據存儲大數據的經驗並不好。當它在4k以下時很好,因爲它像varchar2一樣在本地存儲它。一旦超過4k,你開始看到性能下降。也許,自從我上一次嘗試它之後,事情可能會有所改進,但以下是我在過去爲您提供的信息:

由於客戶端需要通過Oracle服務器獲取LOB,因此可以考慮以下有趣的情況。如果甲骨文 決定緩存它

  • LOB數據將爭奪有限的SGA 緩存與其他數據類型。爲CLOB數據 一般大,所以它可能會推動其他 數據
  • LOB數據得到,如果 甲骨文決定不再緩存它,並 數據流的客戶端磁盤讀取差。
  • 碎片可能是 ,您還沒有遇到過。你會看到你的應用程序是否刪除lob,並且oracle會嘗試重新使用lob。我不知道oracle是否支持在線碎片整理磁盤碎片(他們有索引,但是我們之前嘗試它需要很長時間)。

你提到4個100g的平均20k,所以它是40ms每個魚子。請記住,每個高球需要通過單獨的Lob定位器進行檢索(默認情況下,它不在結果集中)。對於每個吊球來說,這是一個額外的往返行程,我假設(我不是100%確定的,因爲它是前一陣子)如果是這樣的話,我假設每個往返順序至少有5ms額外時間, 對?如果是這樣,你的表現已經首先受到順序吊索取消的限制。您應該能夠通過跟蹤在執行sql與lob lob內容獲取中花費的時間來驗證這一點。或者您可以通過排除帖子中前一個答案建議的lob列來驗證這一點,該列會告訴您它是否與lob有關。

好運

3

我有一個類似的問題,發現JDBC Lobs在訪問lob時進行網絡調用。

從Oracle 11.2g JDBC驅動程序開始,您可以使用預取。 加速訪問10次...

statement1.setFetchSize(1000); 
if (statement1 instanceof OracleStatement) { 
    ((OracleStatement) statement1).setLobPrefetchSize(250000); 
}