2010-08-06 58 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