2014-05-14 80 views
1

我的任務是從Oracle數據庫調用存儲過程。 存儲過程定義如下:如何提高存儲過程的執行性能?

CREATE OR REPLACE PROCEDURE my_st_proc 
    (pname IN VARCHAR2, pdate IN date, o_rc OUT sys_refcursor, o_flag OUT number); 

所以它需要兩個輸入參數,返回兩個輸出參數,其中之一是一個光標。 使用以下代碼測試pl \ sql developer中的性能時,它會在2-3秒內完成。

DECLARE 
    pname varchar2(300) := 'john doe'; 
    pdate date := to_date('01/01/1900','dd/mm/yyyy'); 

    o_flag number; 
    o_data sys_refcursor; 

    --MyRec describes the fields, returned by the cursor 
    TYPE MyRec IS RECORD 
     (cAccount VARCHAR2(20), cBalance number, cDate date, cCurr varchar2(8)); 
    rec MyRec; 
BEGIN 
    my_st_proc(pname,pdate,o_data,o_flag); 
    dbms_output.put_line(o_flag); 

    LOOP 
     FETCH o_data INTO rec; 
     EXIT WHEN o_data%NOTFOUND; 
     dbms_output.put_line(
      rec.cAccount||','||rec.cBalance||','||rec.cDate||','||rec.cCurr); 
    END LOOP; 

    close o_data; 
END; 

但是,當我通過ODP.Net調用存儲過程時,需要多達兩秒的時間才能完成(3 - 5秒)。

const string p_name = "pname"; 
const string p_date = "pdate"; 
const string p_data = "o_data"; 
const string p_flag = "o_flag"; 

using (var connection = new OracleConnection("my connection")) 
{ 
    var command = connection.CreateCommand(); 
    command.CommandType = CommandType.StoredProcedure; 
    command.CommandText = "my_st_proc"; 

    var pname = command.Parameters.Add(p_name, OracleDbType.Varchar2); 
    pname.Direction = ParameterDirection.Input; 
    var pdate = command.Parameters.Add(p_date, OracleDbType.Date); 
    pdate.Direction = ParameterDirection.Input; 

    command.Parameters.Add(p_data, OracleDbType.RefCursor).Direction = 
     ParameterDirection.Output; 

    var pflag = command.Parameters.Add(p_flag, OracleDbType.Int32); 
    pflag.Direction = ParameterDirection.Output; 

    if (command.Connection.State != ConnectionState.Open) 
     command.Connection.Open(); 

    command.Parameters[p_name].Value = name; 
    command.Parameters[p_date].Value = date; 

    DateTime bdate = DateTime.Now; 
    command.ExecuteNonQuery(); 

    if (((OracleDecimal)command.Parameters[p_flag].Value).ToInt32() == 1) 
    { 

    } 
    else 
    { 
     using (var oreader = command.ExecuteReader()) 
     { 
      if (oreader != null) 
      { 
       try 
       { 
        while (oreader.Read()){ } 
       } 
       finally 
       { 
        oreader.Close(); 
       } 
      } 
     } 
    } 
    MessageBox.Show(DateTime.Now.Subtract(bdate).ToString()); 
} 

最耗時的代碼行似乎是

command.ExecuteNonQuery(); 

command.ExecuteReader() 

由遊標返回的行數不超過10 - 15,足以幾並通過閱讀器閱讀它們需要幾毫秒;所以我想這不是FetchSizeRowSize問題。

在這種情況下,我可以做些什麼來提高ODP.Net的性能?

回答

1

首先,你的功能包括打開數據庫。我想在你的其他工具中,你已經完成了連接並執行了命令。根據您的數據庫安全性和位置,這很容易需要1-10秒。

我不認爲這會實際上增加你的秒數,但你從來沒有用過CommandType.StoredProcedure。相反,你自己構建SQL。讓ODP.Net擔心這一點。只需將正確的命令類型和過程名稱作爲文本傳遞即可。

+0

感謝您的回覆。我已經相應地改變了'CommandType'和'CommandText'。然而你是對的,它並沒有提高性能。至於你的第一個想法,它可能是這種情況,儘管我在一個「OracleConnection」中執行該過程以保持它打開。第一個和以下所有調用之間有區別。第一個顯然更長。 – horgh

+0

但以下所有調用仍會持續更長時間,然後從pl sql開發人員工具調用 – horgh

+0

我同意這可能與建立連接有關。通過連接執行循環中的代碼。在循環之外打開,並在循環中(池中應該給出相同的結果)。 –

0

首先確保執行計劃實際上是相同的。

與您的數據庫管理員一起工作,並要求他們爲獨立運行(aqua數據工作室)和您的odp.net調用捕獲解釋計劃,並確認它們實際上是相同的。如果他們不是,那麼這可能會解釋你的問題。然後,您可以嘗試向連接字符串添加「enlist = false」,但更好的方法是讓DBA更新相關表的統計信息,並希望修復緩慢的計劃。有關更多信息,請參閱https://stackoverflow.com/a/14712992/852208

我有這個相同的問題,它歸結爲甲骨文對分佈式事務可能涉及的執行計劃不太樂觀。

以上答案來自:https://stackoverflow.com/a/15886630/852208。這實質上是「從X運行得很好,但不是從Y運行」,所以它可能是重複的,但我們會看到。