2010-08-06 34 views
3

我試圖通過使用數組綁定到OracleParameter來提高我的Oracle SQL查詢的性能。ExecuteReader與Oracle數組綁定

這基本上就是我想要做的事:

   List<string> IDValList = new List<string>(); 
       IDValList.Add("IDOne"); 
       IDValList.Add("IDTwo"); 

       List<int> sizes = new List<int>(); 
       foreach(string id in IDValList) 
       { 
        sizes.Add(id.Length); 
       } 

       using(OracleCommand cmd = new OracleCommand("select col1, col2, col3 from table where col4 in (:idArray)", _conn)) 
       { 
        cmd.CommandType = System.Data.CommandType.Text; 

        OracleParameter arrayParam = new OracleParameter("idArray", OracleDbType.Varchar2); 
        arrayParam.Direction = System.Data.ParameterDirection.Input; 
        arrayParam.Value = IDValList.ToArray(); 
        arrayParam.ArrayBindSize = sizes.ToArray(); 

        cmd.ArrayBindCount = IDValList.Count; 
        cmd.Parameters.Add(arrayParam); 

        using(OracleDataReader dr = cmd.ExecuteReader()) 
        { 
         while(dr.Read()) 
         { 
          // now read the row... 

這編譯和運行,但我總是隻能拿回一排,第一個ID。就像它忽略參數中數組中其餘的值一樣。

有趣的是,參數的ArrayBindStatus對所有的值都是成功的。

我錯過了什麼?或者這不適用於OracleReader?

感謝

編輯:基本上,我想以此爲榜樣,但我希望能夠讀取使用DataReader查詢生成的數據集。

http://www.oracle.com/technology/oramag/oracle/09-sep/o59odpnet.html

+0

您是否找到解決方案? – aggsol 2015-04-27 09:56:38

+0

我不認爲我們曾經這樣做過。我記得我們用硬編碼的方式編碼... – MonkeyWrench 2015-06-09 19:43:07

+0

根據這個問題,http:// stackoverflow。com/questions/25401787/c-odp-net-large-in-clause-workaround,請參閱Tyree Jackson的評論「例如,ArrayBindCount的使用受Oracle限制僅用於ExecuteNonQuery(更新/插入/刪除)語句「。我無法從Oracle文檔中確認這一點,但這也是我的經驗。 – VinceJS 2016-09-26 13:33:00

回答

-1

它將作品:

using 
    (OracleCommand cmd = 
    new OracleCommand("select col1, col2, col3 from table where col4 in (" + string.Join(",", IDValList) + ")", _conn)) 

,因爲現在你只是傳遞第一個元素,從你的列表中。

+0

這會工作,但不是我想要做的。我想使用綁定變量來提高這些查詢的性能。 – MonkeyWrench 2010-08-06 11:25:51

+0

看起來那麼這樣的回答:http://stackoverflow.com/questions/337704/parameterizing-a-sql-in-clause/337792#337792可能是它可以幫助你 (坦率地說,不要以爲綁定變量莫名其妙在這種特殊情況下的性能表現)。 – 2010-08-06 11:30:02

1

有幾種方法可以用來搜索「列表中的變量」。利用綁定參數。

這是基於這樣的: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:210612357425

坦白說,我試着儘可能多,如果不只是爲提高性能,但出於安全的其他級別使用綁定變量。

雖然有很多方法對皮膚一隻貓,這(而詳細)應該做

在甲骨文 --create你的類型 創建或替換型varcharTableType爲VARCHAR2(255)的表;

--create your function 
function in_varchar(p_string in varchar2) return varcharTableType 
    as 
     l_string  long default p_string || ','; 
     l_data   varcharTableType := varcharTableType(); 
     n    number; 
    begin 
     loop 
      exit when l_string is null; 
      n := instr(l_string, ','); 
     l_data.extend; 
     l_data(l_data.count) := 
       ltrim(rtrim(substr(l_string, 1, n-1))); 
     l_string := substr(l_string, n+1); 
    end loop; 

    RETURN L_DATA; 
    END in_varchar; 

現在ammend查詢在.NET

col4 in (select COLUMN_VALUE from table(in_varchar(:idArray))) 

(順便說一句我複製大多數代碼從以前的帖子我在Oracle論壇上回答: http://forums.oracle.com/forums/thread.jspa?messageID=4299793&#4299793

這實際上使它所以你不必使用數組綁定,只要確保這是一個逗號分隔的字符串::idArray =「A,B,C」

另一個op重刑是對select語句返回到REF光標數組:

 /* example table 
     * 
Create Table Zzztab(Deptno Number, Deptname Varchar2(50) , Loc Varchar2(50) , State Varchar2(2) , Idno Number(10)) ; 
/
insert into Zzztab(Deptno , Deptname , Loc , State , Idno) 
values (0,'Zero','US','NY',0); 
insert into Zzztab(Deptno , Deptname , Loc , State , Idno) 
values (1,'One','CA','ON',1); 
insert into Zzztab(Deptno , Deptname , Loc , State , Idno) 
values (2,'Three','IS',null,2); 
insert into Zzztab(Deptno , Deptname , Loc , State , Idno) 
values (3,'Four','BD',null,3); 
     */ 
    string connectStr = GetConnectionString(); 

    // Initialize array of data 
    String[] myArrayDeptName = { "Zero", "Three", "Four" }; 

    OracleConnection connection = new OracleConnection(connectStr); 
    OracleCommand command = new OracleCommand(); 
    command.Connection = connection; 
    command.CommandType = CommandType.Text ; 
    command.CommandText = "begin open :cur for SELECT DEPTNO, DEPTNAME FROM ZZZTAB WHERE DEPTNAME = :DEPT; end;"; 

    command.ArrayBindCount = myArrayDeptName.Length ; 
    command.BindByName = true; 

    OracleParameter cur = new OracleParameter("cur", OracleDbType.RefCursor); 
    cur.Direction = ParameterDirection.Output; 
    cur.Value = myArrayDeptName; 
    command.Parameters.Add(cur); 

    // deptname parameter 
    OracleParameter deptNameParam = new OracleParameter("DEPT", OracleDbType.Varchar2); 
    deptNameParam.Direction = ParameterDirection.Input; 
    deptNameParam.Value = myArrayDeptName; 
    command.Parameters.Add(deptNameParam); 

    try 
    { 
     connection.Open(); 
     command.ExecuteNonQuery(); 

     foreach (Oracle.DataAccess.Types.OracleRefCursor rc in (Oracle.DataAccess.Types.OracleRefCursor[])cur.Value) 
     { ... fill in an join the datatables 

您可以使用完全相同的邏輯,只是有列返回到每個各自爲陣。

+0

應該有這樣做的方法,無需在PL/SQL的C#中進行各種字符串操作和串聯操作。 – MonkeyWrench 2010-08-06 12:49:27

+0

增加了另一種方式......但是這個返回一個Oracle.DataAccess.Types.OracleRefCursor [],但不需要任何pl/sql。但是你會運行所述查詢(批量)數組的次數 – Harrison 2010-08-06 14:10:35