2009-01-23 179 views
0

希望有人可以對我目前與Oracle數據庫有關的問題發表一些看法 - 我確定這很簡單!閱讀CLOB列很慢

我已經成功的樣本中重建這一點,所以這裏是數據庫結構:

CREATE TABLE MyTable(
    ixMyTable NUMBER, 
    clobData CLOB 
) 
/

CREATE OR REPLACE PACKAGE PKGTEST 
AS 
    PROCEDURE DoSomething(
     cur_OUT OUT SYS_REFCURSOR 
     ); 
END PKGTEST; 
/

CREATE OR REPLACE PACKAGE BODY PKGTEST 
AS 

PROCEDURE DoSomething(
    cur_OUT OUT SYS_REFCURSOR 
) 
AS 
BEGIN 
    OPEN cur_OUT FOR 
     SELECT ixMyTable, clobData 
     FROM MyTable; 
END; 

END PKGTEST; 
/

GRANT EXECUTE ON PKGTEST TO TEST_ROLE 
/

BEGIN 
    FOR i IN 1 .. 7000 LOOP 
     insert into mytable values (i, TO_CLOB('123456')); 
    END LOOP; 
END; 
/

額外的信息:

模式所有者是TEST_SCHEMA

用戶是CARL

CARL具有TEST_ROLE角色

鑑於數據庫設置如上所述,我有一個C#測試應用程序,它使用標準的System.Data.OracleClient.OracleCommand等來執行PKGTEST.DoSomething並將結果扔到數據網格(DevExpress)中。

很確定這裏的網格是不相關的,因爲我們通過C++使用開源OTL(不是我的部門,幸運的是)經歷了同樣的問題。

OK,這個問題....從開始

時間,直到填充網格〜35-40s,哎喲。

但是,如果我做到以下幾點:

GRANT SELECT ON MyTable TO TEST_ROLE 
/

,然後再次執行查詢時,它需要〜5-6s。

在我看來,這與特權等有關,但我不太確定它爲什麼仍然實際上兩種方式?

只是扔別的東西放入鍋中,如果我改變的過程

SELECT ixMyTable, TO_CLOB(TO_NCLOB(clobData)) 
FROM MyTable; 

那麼時間約5-6s,有或沒有額外的SELECT權限。

任何指針或直出解決方案將不勝感激!

編輯:

操作系統是Vista x86系統業務

Oracle服務器是10.2.0.1

Oracle客戶端是10.2.0.3

編輯:

至於建議,我我已經嘗試從MS OracleClient更改爲ODP.NET,並且按要求加速。

不幸的是,這是受到影響的C#應用​​程序只是其用於查看錶/運行存儲過程等

我們的主要遞送是使用OTL(http://otl.sourceforge.net/otl3_intro.htm),用於訪問數據庫的C++程序的內部應用程序。這不是真的可以在這個時候改變,所以我真的很想理解差異的原因,而不必無所顧忌地選擇GRANT SELECT。

如果缺乏SELECT權限導致完全失敗,那麼我可能會忍受這一點,但是缺少SELECT似乎會導致訪問CLOB數據的一些較慢的路由。

我已經標出了3個答案 - 感謝那些 - 但我真的可以做一個理由,所以我會添加一個賞金。

P.S.我們真的很想和OCCI一起參與我們的C++,但是由於Oracle在目前我們始終支持IDE的一個版本,所以我們無法讓它與我們的Visual Studio 2008良好地配合。

回答

6

您確定你每次都從磁盤讀取blob,而不是從磁盤緩存讀取第二個和之後的數據?

我在性能測試中看到過這個問題,特別是在Oracle上,第一次運行測試非常糟糕。然後,有一次未成年人(看起來無足輕重的變化)表現突然改善。但真正發生的是,您正在查詢的數據已被加載到緩存中,並且可以以10倍或20倍的速率訪問(內存與磁盤)。

執行此測試的正確方法是在查詢運行之間反彈數據庫。如果DBA不允許您將測試生產服務器彈回此測試,請在您的計算機上加載Oracle XE的副本。

編輯:或者更好:每次刪除並重新創建表。你可能會這樣做,但沒有提到它。

+0

+1;關於緩存的好建議。 – DCookie 2009-01-23 18:26:41

+0

是的,我們在進行性能測試之前就遇到了緩存問題,但這是一個一致的速度問題。即使是第一次使用TO_CLOB(TO_NCLOB())技術的調用也很快,我不希望這會在第一次運行時碰到緩存。謝謝。 – Carl 2009-01-24 07:43:25

1

根據以上建議,您可以嘗試不同的ODBC驅動程序或客戶端軟件。 TO_CLOB(TO_NCLOB())的工作速度如此之快,直接的一個似乎並沒有表明問題存在。

首先,我將採取兩個查詢,並通過SQLDeveloper運行它們並獲得解釋計劃。這應該爲您提供Oracle方面的執行基準。添加轉換應該對執行路徑沒有影響。交替地運行查詢和時間以查看它們的速度。如果沒有區別,我會建議客戶端軟件是您的問題。

如果我的假設是正確的,這也將解釋GRANT SELECT更改。客戶端軟件正在CLOB上進行某種昂貴的轉換。授予和/或顯式轉換允許客戶避免這種情況。我不知道爲什麼。

0

我真的認爲這裏的問題是OTL驅動程序和OracleClient在處理來自SYS_REFCURSOR的CLOB時遇到問題。 SYS_REFCURSORs很弱,這意味着遊標本身可以返回任何類型的數據,這意味着驅動程序需要不斷返回數據庫並查詢遊標的元數據(即獲取遊標中的數據類型),然後加載CLOB流,然後加載數據。顯然,如果執行查詢的用戶可以訪問被查詢的表,那麼驅動程序可以更好地檢索元數據並返回正確的數據。

是否更改存儲過程以返回強大的ref_cursor工作?

CREATE OR REPLACE PACKAGE PKGTEST 
    AS 
    TYPE C_DoSomething IS REF CURSOR RETURN MyTable%ROWTYPE; 
    PROCEDURE DoSomething(
     cur_OUT OUT c_DoSomething 
    ); 
END PKGTEST; 

您可以更改存儲過程做TO_CLOB(),因爲這似乎也工作?

+0

不幸的是,返回一個強大的光標並沒有什麼區別。可以更改存儲過程,但是TO_CLOB()本身不起作用 - 它必須是TO_CLOB(TO_NCLOB())。我不確定這些電話實際上做了什麼,也就是說,它們有多昂貴? – Carl 2009-01-28 09:46:25

0

什麼是您的數據庫的NLS_CHARACTERSET和NLS_NCHAR_CHARACTERSET。運行

select * from nls_database_parameters; 

得到結果。您的客戶端軟件的NLS_LANG設置是什麼?

這可能會提供一些更深入的問題,並有助於回答TO_CLOB(TO_NCLOB())調用的代價有多昂貴的問題。

0

這些並不一定都是直接相關的,但是如果它們相關,你可能應該檢查每一個。我懷疑這是緩存相關的:一旦你完成你的第一個查詢,然後應用select,然後它運行得很快。如果你想正確地進行性能測試,在中間你必須彈出服務器來擺脫緩存。如果您執行此測試並突然執行得更好,請嘗試將表格固定到緩存中。請參閱下面的內聯clob存儲,因爲這可能是相關的。

我在Oracle 10g一年左右的clob性能方面遇到了問題。一旦我們獲得了令人敬畏的dba的幫助,我們就解決了其中的大部分問題。花了大約2個月的時間纔將性能提升到足夠的速度。

您正在使用哪個版本的Oracle? 在Oracle 10g(早期版本)中,clob性能存在大量問題。實際上,在某些情況下,使用兩個表和一個varchar列(將varchars連接在一起,並且有clob)實際上速度更快。我們升級到更高版本,這是好得多

此外,您的數據存儲在哪裏? 還有一個選項可以將clob存儲在表格中。根據您的數據的大小,您可能會發現這有助於提高性能。 如果您將數據存儲在SAN上,則還需要查看SAN上的高速緩存大小以及塊大小。當緩存大小不正確時,Oracle + SAN可能會有點有趣。

另一個解決方法: 如果您發現持久性較慢,或者訪問速度緩慢且未綁定CPU,則將數據壓縮並將其存儲在Blob中。我們在這裏也看到了很大的性能優勢。

如果在處理clob時看到性能問題(內存相關?),我們發現我們會將對象重新創建爲新字符串。即使數據較小,驅動程序也會預先創建32K大小的字符串。

我確實懷疑係統表是否可能被分割?有很多表/模式嗎?同義詞呢?

另外,當你存儲clobs時,不要將它們存儲到Oracle的一個海量文件中嗎?如果我沒有記錯,你必須小心碎片化;存儲不會被釋放以供重用。

也許你可以把一個.NET Web服務放在你的數據庫前面?如果您無法解決性能問題,那麼這可能是一種選擇。