2010-08-06 11 views
3

J'essaie d'améliorer les performances de mes requêtes SQL Oracle en utilisant la liaison de tableau à un OracleParameter.ExecuteReader avec la liaison de tableau Oracle

C'est essentiellement ce que je suis en train de faire:

   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... 

Cette compile et fonctionne, mais je reçois toujours seulement en arrière une ligne, pour la première ID. C'est comme son ignorant le reste des valeurs dans le tableau dans le paramètre.

Fait intéressant, le ArrayBindStatus du paramètre est réussi pour toutes les valeurs.

Qu'est-ce qui me manque? Ou cela ne fonctionnera pas avec un OracleReader?

Merci

Edit: En fait, je suis en train de suivre cet exemple, mais je veux être en mesure de lire l'ensemble de données résultant de la requête à l'aide d'un DataReader.

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

+0

Avez-vous trouvé une solution pour cela? – aggsol

+0

Je ne pense pas que nous ayons jamais fait. Je rappelle que nous l'avons codé à la dure ... – MonkeyWrench

+0

Selon cette question, http: // stackoverflow.com/questions/25401787/c-odp-net-large-in-clause-solution, voir le commentaire de Tyree Jackson "L'utilisation de ArrayBindCount par exemple est limitée par Oracle pour une utilisation dans les instructions ExecuteNonQuery (Update/Insert/Delete) " Je ne peux pas le confirmer à partir des documents Oracle, mais cela a été mon expérience aussi. – VinceJS

Répondre

-1

œuvres: il sera

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

parce que maintenant vous venez de passer premier élément de votre liste.

+0

Cela fonctionnera, mais pas ce que je veux faire. Je veux utiliser des variables de liaison pour améliorer les performances de ces requêtes. – MonkeyWrench

+0

regardez alors dans cette réponse: http://stackoverflow.com/questions/337704/parameterizing-a-sql-in-clause/337792#337792 peut être cela vous aide (Franchement, ne pensez pas que les variables de liaison en quelque sorte améliorer la performance dans ce cas particulier). –

1

Il y a plusieurs façons de faire la "variable dans la liste" que vous recherchez. Pour utiliser un paramètre lié.

Ceci est basé sur ce point: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:210612357425

aussi souvent que possible

franchement j'essaie d'utiliser des variables de lierait si non seulement pour l'augmentation des performances, mais aussi pour le niveau de sécurité supplémentaire.

alors qu'il ya plusieurs façons de peau d'un chat, ce (tout bavard) doit faire

dans Oracle --create votre type créer ou remplacer le type varcharTableType comme table des 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; 

maintenant ammend votre requête dans .net

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

(BTW I copié la plupart de ce code d'un précédent commentaire j'ai répondu sur les forums d'oracle: http://forums.oracle.com/forums/thread.jspa?messageID=4299793&#4299793

cela fait faire donc vous ne devriez pas utiliser la liaison de tableau, assurez-vous juste que c'est une chaîne délimitée par des virgules:: idArray = "A, B, C"

Une autre op tion est de renvoyer les instructions select dans un tableau de curseur 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 

vous pouvez utiliser exactement la même logique et juste les colonnes retourner dans chacune leur propre tableau.

+0

Il devrait y avoir un moyen de le faire sans avoir à faire toutes sortes de manipulation de chaînes et de concaténation, que ce soit en C# de PL/SQL. – MonkeyWrench

+0

ajouté d'une autre manière ... celui-ci renvoie cependant un Oracle.DataAccess.Types.OracleRefCursor [] mais ne nécessite pas de pl/sql. mais vous exécuterez cette requête (en batch) le nombre de fois du tableau – Harrison