2016-02-10 1 views
2

La commande SqlCommand suivante fonctionne correctement sans problèmes de performances apparents lorsque la procédure stockée SelectNewObjects renvoie quelques enregistrements (~ 500). Cependant, quand il retourne plus de 1000 disques, je commence à des problèmes de performance:Amélioration des performances d'une boucle while (code C#) appelant une procédure stockée T-SQL

using (SqlCommand cmdAddNewObject = new SqlCommand("SelectNewObjects", con)) 
{ 
    cmdAddNewObject.CommandType = CommandType.StoredProcedure; 
    cmdAddNewObject.Parameters.AddWithValue("@parameter1", parameter1); 
    using (SqlDataReader rdrAddNewObject = cmdAddNewObject.ExecuteReader()) 
    { 
     while (rdrAddNewObject.Read()) 
     { 
      if (rdrAddNewObject.GetString(0) != null) 
      { 
       try 
       { 
        addObject(parameter1, rdrAddNewObject.GetString(0), rdrAddNewObject.GetString(0).Length/4, rdrAddNewObject.GetString(0).Substring(0, 2), 
         rdrAddNewObject.GetString(0).Substring(2, 2), rdrAddNewObject.GetString(1)); 
        if (rdrAddNewObject.GetString(1) == "No description found") 
        { 
         // Do something 
        } 
        else 
        { 
         // Do something else 
        } 
       } 
       catch (Exception ex) 
       { 
        // Throw exception 
       } 
      } 
     } 
    } 
} 

En mots simples, ce que je fais ici est d'appeler une méthode (addObject) pour chaque enregistrement renvoyé par SelectNewObjects.

Quelques détails:

  • SelectNewObjects renvoie les enregistrements d'une table temporaire créé au large Tableau 1.

  • Dans le if/else bloc que je mets à jour un champ de Tableau 1 du dossier mentionnées dans le tableau temporaire après l'exécution de addObject finalise.

  • La méthode addObject insère chaque enregistrement trouvé dans la table temporaire SQL dans un système Oracle distinct via l'utilisation de SOA (Service-Oriented Architecture). Je n'ai pas eu accès à la base de données sous-jacente, donc j'ai dû me contenter de cette façon de faire les choses.

  • Il y a des moments où la table temporaire devrait avoir plus de 20.000 enregistrements (seulement deux champs: chacun Nom et Description de) si cela peut rapidement devenir un cauchemar.

À un moment donné, le pool d'applications échouera avec les deux erreurs suivantes (prises à partir de l'IIS 7 Observateur d'événements Windows):

  • ID d'événement 5013:Un processus de demande au service pool '.NET v4.5' dépassé les limites de temps lors de l'arrêt. L'ID du processus était '5616'.

  • ID d'événement 5138:Un processus de travail « 5616 » pool d'applications servant » v4.5' .NET n'a pas réussi à arrêter un canal d'écoute pour le protocole « http » dans le temps imparti. Le champ de données contient le numéro d'erreur.

La description de ces ID d'événement dans technet.microsoft.com et support.microsoft.com ne jettent pas trop de lumière sur cette question de la performance et ne sont pas concluantes quant à sa cause. Cela dit, y a-t-il un moyen d'améliorer le code C# pour gérer des dizaines de milliers d'enregistrements renvoyés par le SP, et d'effectuer une action sur chacun plus rapidement?

+0

Si le goulot d'étranglement dans le code C# est certain? Quels sont les horaires si vous devez exécuter la même procédure stockée dans Management Studio? – Alex

+0

Divisez le problème en deux: mettez en commentaire l'intérieur de la boucle while et vérifiez si la procédure stockée et les temps d'extraction des données sont acceptables. – HABO

Répondre

1

Je suppose que c'est parce qu'il faut beaucoup de temps pour insérer dans le DB Oracle sur le fil ainsi que garder votre connexion SQL ouverte plus longtemps qu'elle ne devrait être ouverte.Par conséquent, vous voulez stocker vos données dans une collection temporaire alors soit en boucle dans la liste ou l'envoyer en vrac (si vous faites ce dernier, vous aurez besoin de le casser ou vous frapperez une limite)

par exemple

List<ObjectToStoreInOracle> items = new List<ObjectToStoreInOracle>(); 

    using (SqlCommand cmdAddNewObject = new SqlCommand("SelectNewObjects", con)) 
    { 
     cmdAddNewObject.CommandType = CommandType.StoredProcedure; 
     cmdAddNewObject.Parameters.AddWithValue("@parameter1", parameter1); 
     using (SqlDataReader rdrAddNewObject = cmdAddNewObject.ExecuteReader()) 
     { 
      while (rdrAddNewObject.Read()) 
      { 
       if (rdrAddNewObject.GetString(0) != null) 
       { 
        try 
        { 
         // add items to temp array list 
         items.Add(new ObjectToStoreInOracle(parameter1, rdrAddNewObject.GetString(0), rdrAddNewObject.GetString(0).Length/4, rdrAddNewObject.GetString(0).Substring(0, 2), rdrAddNewObject.GetString(0).Substring(2, 2), rdrAddNewObject.GetString(1)))) 

         if (rdrAddNewObject.GetString(1) == "No description found") 
         { 
          // Do something 
         } 
         else 
         { 
          // Do something else 
         } 
        } 
        catch (Exception ex) 
        { 
         // Throw exception 
        } 
       } 
      } 
     } 
    } 

    AddToOracleDB(items) 


    private void AddToOracleDB(List<ObjectToStoreInOracle> items){ 

    //do stuff here to add to the Oracle DB 
    } 
+0

Merci pour le conseil de stocker les données dans un objet List - je l'ai fait et je ne rencontre plus ces problèmes pour ce SP particulier. Je vais répliquer cette solution dans une autre partie du code (une autre boucle en invoquant une requête INSERT vers la base de données SQL) pour améliorer cela aussi. Merci encore! – gacanepa