2013-12-12 145 views
1

在我的公司我們有一個WPF應用程序,它可以連接到不同的數據庫(MS SQL,MySQL,SQLite和Oracle)。我們有很多表(有時200+,不問爲什麼,它非常複雜),我們的數據訪問層有幾個接口和虛擬/重寫方法來處理特定數據庫中的數據讀取。這很重要,因爲大多數教程都沒有專門針對某個表格進行工作,而是我們已經動態創建了需要運行的特定於數據庫的命令。在MS SQL,MySQL和SQLite下一切正常,但在Oracle CLOB中讀取速度很慢。要讀取2000行數據,需要40-50秒。不幸的是,在大多數情況下,我們不能假定我們不需要CLOB類型,因爲我們以xml格式存儲財務數據,有時超過4000,8000甚至10k + char-long大小。使用ODP.Net解決方案來讀取數據Im,這就是即時通訊做:如何在.Net中有效地處理從Oracle中緩慢的CLOB讀取?

我們的環境: 甲骨文:11.2.0.1.0 VS:2010,專業版 Oracle.DataAccess.dll是從我的Oracle主引用安裝: C:\ ORACLE \ ODP.NET \ BIN \ 4 \ Oracle.DataAccess.dll

而且我testcode(從我們的解決方案):

物業:

private string ConnectionString 
{ 
    get 
    { 
     return 
     string.Format(
     "User Id={0}; Password={1}; POOLING=true; 
     Data Source= (DESCRIPTION=(ADDRESS= 
     (PROTOCOL=TCP)(HOST={2})(PORT={3})) (CONNECT_DATA=(SID={4}) 
     (SERVICE_NAME={5})));", 
     "ourUser", "ourPassword", "ourHost", "ourPort", "ourSID", 
     "ourDatabaseName"); 
     } 
    } 

的命令來運行:

string sql = "SELECT * FROM OurTable"; 
//This table contains at least one CLOB column 

而我們的測試代碼:

List<object[]> readerList = new List<object[]>(); 

using (Oracle.DataAccess.Client.OracleConnection oraConn = new 
    Oracle.DataAccess.Client.OracleConnection(ConnectionString)) 
{ 
    oraConn.Open(); 
    Oracle.DataAccess.Client.OracleCommand oraComm = new 
     Oracle.DataAccess.Client.OracleCommand(sql); 
    oraComm.CommandType = CommandType.Text; 
    oraComm.Connection = oraConn; 
    Oracle.DataAccess.Client.OracleDataReader oraReader; 
    oraReader = oraComm.ExecuteReader(); 
    oraComm.InitialLOBFetchSize = -1; 

    while (oraReader.Read()) 
    { 
     object[] readObjects = new object[oraReader.FieldCount]; 
     oraReader.GetValues(readObjects); 
     readerList.Add(readObjects); 
    } 

    oraConn.Close(); 
} 

的同時迭代運行非常緩慢,除非我們不需要讀CLOB在這這將是快。 不幸的是,我不能製作特定於表格的解決方案,因爲在每種情況下我都不知道我需要處理哪些表格(有時會有動態創建的表格)。

因此,問題: 是否有任何解決方案使其與從MS SQL讀取TEXT類型對象一樣快?

回答

0

真的很難說究竟是什麼導致了緩慢。但我很確定clob不應該像這樣慢下來。

很好地縮小C#代碼(odp.net訪問方式)還是oracle服務器是根本原因。在oracle方面有多種方法可以識別。我會嘗試的第一件事就是使用SET AUTOTRACE ON在sql * plus上執行SQL,這將告訴我們在oracle服務器上的行爲如何。

  • 此外,有幾個猜測或建議,我們可以基於您的帳戶 。如果你的數據長度總是小於32K和 你可以升級oracle到12c,比試試varchar2代替clob或 blob,因爲12c中的varchar2已經擴展到32K;
  • LOB存儲是lob的重要選項。 「選擇 dbms_metadata.get_ddl('TABLE','your table')from dual;」將告訴 表中的選項。對我來說「ENABLE STORAGE IN ROW」應該總是使用 。有關此選項的詳細信息,請參閱 http://docs.oracle.com/cd/B28359_01/appdev.111/b28393/adlob_tables.htm#i1012988
0

有在Command對象一看屬性FetchSize,在這裏看到:Improve ODP.NET Performance

你可以得到行這樣的尺寸:

Public Function GetRowSize(ByVal cmd As OracleCommand) As Integer 
     Dim dr As OracleDataReader 
     dr = cmd.ExecuteReader() 
     Return CInt(dr.GetType.GetField("m_rowSize", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic).GetValue(dr)) 
    End Function 

在C#中,它看起來像這樣:

public int GetRowSize(OracleCommand cmd) 
{ 
    OracleDataReader dr = cmd.ExecuteReader(); 
    return (int)(dr.GetType().GetField("m_rowSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dr)); 
} 

Yo你可以在應用程序啓動時爲每個不同的查詢執行一次這個函數,然後你可以重用這個值。

我記得前段時間我有類似的問題。我的解決方案是選擇沒有任何CLOB列的表。爲了獲得CLOB值,我只對單個CLOB列和單個記錄運行額外的SELECT(像您一樣使用OracelDataReader)。

我還發現這個文檔:Obtaining LOB Data

+0

我試着爲不同的值設置FetchSize。 RowSize在我當前的測試中爲176,但它不能解決我的問題。再一次,只有CLOB處理速度很慢。對於「小」類型,一切都很快。 我聽說.Net無法包含CLOB,並嘗試將其轉換爲其他數據類型,這就是爲什麼它慢...不知道這是否正確...? – Daniel