2010-07-21 5 views
3

J'importe les données à partir de trois fichiers délimités par des tabulations dans les DataTables et après cela, je dois parcourir toutes les lignes de la table principale et trouver toutes les lignes dans deux tables enfants. Contre chaque tableau DataRow [] que j'ai trouvé à partir des tables enfant, je dois à nouveau passer individuellement chaque ligne et vérifier les valeurs en fonction de différents paramètres et à la fin je dois créer un enregistrement final qui fusionnera maître et deux enfants colonnes de table. Maintenant, j'ai fait cela et son fonctionnement, mais le problème est sa performance. J'utilise le DataTable.Select pour trouver toutes les lignes enfants de la table enfant qui, je crois, le rendent très lent. Rappelez-vous s'il vous plaît le Aucun de la table a une clé primaire que les lignes en double sont acceptables. Pour le moment, j'ai 1200 lignes dans la table principale et 8000 lignes dans la table des enfants et le temps total nécessaire est de 8 minutes.DataTable.Select et problème de performances dans C#

Toute idée comment puis-je augmenter la performance. Merci à l'avance

Le code est ci-dessous ***************

DataTable rawMasterdt = importMasterFile(); 
DataTable rawDespdt = importDescriptionFile(); 

     dsHelper = new DataSetHelper(); 
     DataTable distinctdt = new DataTable(); 
     distinctdt = dsHelper.SelectDistinct("DistinctOffers", rawMasterdt, "C1"); 

     if (distinctdt.Rows.Count > 0) 
     { 
      int count = 0; 
       foreach (DataRow offer in distinctdt.Rows) 
       { 
        string exp = "C1 = " + "'" + offer[0].ToString() + "'" + ""; 
        DataRow masterRow = rawMasterdt.Select(exp)[0]; 

        count++; 
        txtBlock1.Text = "Importing Offer " + count.ToString() + " of " + distinctdt.Rows.Count.ToString(); 
        if (masterRow != null) 
         { 
          Product newProduct = new Product(); 

          newProduct.Code = masterRow["C4"].ToString(); 
          newProduct.Name = masterRow["C5"].ToString(); 
          // ----- 
          newProduct.Description = getProductDescription(offer[0].ToString(), rawDespdt); 
          newProduct.Weight = getProductWeight(offer[0].ToString(), rawDespdt); 
          newProduct.Price = getProductRetailPrice(offer[0].ToString(), rawDespdt); 
          newProduct.UnitPrice = getProductUnitPrice(offer[0].ToString(), rawDespdt); 
          // ------- more functions similar to above here 

          productList.Add(newProduct); 
         } 
       } 
       txtBlock1.Text = "Import Completed"; 
public string getProductDescription(string offercode, DataTable dsp) 
    { 
     string exp = "((C1 = " + "'" + offercode + "')" + " AND (C6 = 'c'))"; 
     DataRow[] dRows = dsp.Select(exp); 
     string descrip = ""; 
     if (dRows.Length > 0) 
     { 
      for (int i = 0; i < dRows.Length - 1; i++) 
      { 
       descrip = descrip + " " + dRows[i]["C12"]; 
      } 
     } 
     return descrip; 

    } 
+1

Postez votre code. Cette quantité de données ne devrait pas causer de problèmes, nous avons donc besoin de voir votre code pour comprendre les problèmes. – Oded

+0

s'il vous plaît voir le code ci-dessus –

Répondre

0

DataTables peut être fait d'avoir des relations avec d'autres DataTables dans un DataSet. Voir http://msdn.microsoft.com/en-us/library/ay82azad%28VS.71%29.aspx pour un peu de discussion et comme point de départ pour la navigation. Je n'ai pas beaucoup d'expérience de les utiliser mais si je comprends bien, ils feront ce que vous voulez (en supposant que vos tableaux sont dans un format approprié). Je suppose que ceux-ci ont une plus grande efficacité qu'un processus manuel de faire de même, mais je peux me tromper. Peut-être vaut-il la peine de voir si elles fonctionnent pour vous et l'analyse comparative pour voir si elles sont une amélioration ou non ...

+0

Merci pour votre réponse Chris mais je crains que je ne peux pas utiliser cela parce que je n'ai pas PK, FK dans ce scénario. Comme je l'ai dit plus tôt, il n'y a pas PK et toutes les tables peuvent avoir les lignes en double. –

+0

@ Jhelumi786: Je n'aurais pas pensé que vous aviez besoin d'une clé primaire * unique * pour l'utiliser. J'ai toujours pensé à cela comme faire une jointure dans SQL de cette façon. Comme je le dis bien, je ne l'ai pas utilisé depuis longtemps, donc je ne m'en souviens pas vraiment. :) – Chris

3

Vous pouvez accélérer beaucoup en utilisant un dictionnaire. Par exemple:

if (distinctdt.Rows.Count > 0) 
{ 
    // build index of C1 values to speed inner loop 
    Dictionary<string, DataRow> masterIndex = new Dictionary<string, DataRow>(); 
    foreach (DataRow row in rawMasterdt.Rows) 
     masterIndex[row["C1"].ToString()] = row; 

    int count = 0; 
    foreach (DataRow offer in distinctdt.Rows) 
    { 

Puis à la place de

string exp = "C1 = " + "'" + offer[0].ToString() + "'" + ""; 
    DataRow masterRow = rawMasterdt.Select(exp)[0]; 

Vous devez faire cela

DataRow masterRow; 
if (masterIndex.ContainsKey(offer[0].ToString()) 
    masterRow = masterIndex[offer[0].ToString()]; 
else 
    masterRow = null; 
0

Avez-vous couru à travers un profileur? Cela devrait être la première étape. Quoi qu'il en soit, cela peut aider:

  • Lire le fichier texte maître dans la ligne ligne par ligne. Mettez la fiche dans un dictionnaire comme clé. Ajoutez-le à l'ensemble de données (1 passe par le maître).

  • Lire la ligne de fichier texte enfant en ligne, ajoutez cela comme une valeur pour la fiche appropriée dans le dictionnaire créé ci-dessus

  • Maintenant, vous avez tout dans le dictionnaire en mémoire, en faisant seulement 1 passe à travers chaque fichier . Effectuez un dernier passage dans le dictionnaire/les enfants et traitez chaque colonne et effectuez les calculs finaux.

1

Si vous créez un DataRelation entre votre parent et DataTables enfant, vous pouvez consulter les lignes enfants en invoquant DataRow.GetChildRows (DataRelation) sur la ligne parente (resp. DataRow.GetChildRelName en cas de groupes de données typés). La recherche appliquera une recherche TreeMap, et les performances devraient être bonnes même avec beaucoup de lignes enfants. Dans le cas où vous devez rechercher des lignes basées sur d'autres critères que sur les clés étrangères d'une DataRelation, je recommande d'utiliser DataView.Sort/DataView.FindRows() au lieu de DataTable.Select(), dès que vous devez interroger les données plus d'une fois.DataView.FindRows() sera basé sur la recherche TreeMap (O (log (N)), où DataTable.Select() doit analyser toutes les lignes (O (N).) Cet article contient plus de détails: http://arnosoftwaredev.blogspot.com/2011/02/when-datatableselect-is-slow-use.html

4

4.5 .Net et la question est toujours là.

Voici les résultats d'une référence simple où DataTable.Select et différentes implémentations de dictionnaire sont comparés pour le temps CPU (les résultats sont en millisecondes)

#Rows Table.Select Hashtable[] SortedList[] Dictionary[] 
    1000  43,31   0,01   0,06   0,00 
    6000  291,73   0,07   0,13   0,01 
    11000  604,79   0,04   0,16   0,02 
    16000  914,04   0,05   0,19   0,02 
    21000  1279,67   0,05   0,19   0,02 
    26000  1501,90   0,05   0,17   0,02 
    31000  1738,31   0,07   0,20   0,03 

problème :

La méthode DataTable.Select crée une instance de classe "System.Data.Select" en interne et cette classe "Select" crée des index basés sur les champs (colonnes) spécifiés dans la requête. La classe Select réutilise les index créés, mais l'implémentation DataTable ne réutilise pas l'instance de la classe Select. Par conséquent, les index sont recréés chaque fois que DataTable.Select est appelée. (Ce comportement peut être observé par décompilation System.Data)

Solution:

On suppose la requête suivante

DataRow[] rows = data.Select("COL1 = 'VAL1' AND (COL2 = 'VAL2' OR COL2 IS NULL)"); 

Au lieu de cela, créer et remplir un dictionnaire avec les touches correspondant aux différentes combinaisons de valeurs des valeurs des colonnes utilisées comme filtre. (Cette opération relativement coûteuse doit être effectuée qu'une seule fois et l'instance dictionnaire doit ensuite être réutilisé)

Dictionary<string, List<DataRow>> di = new Dictionary<string, List<DataRow>>(); 

foreach (DataRow dr in data.Rows) 
{ 
    string key = (dr["COL1"] == DBNull.Value ? "<NULL>" : dr["COL1"]) + "//" + (dr["COL2"] == DBNull.Value ? "<NULL>" : dr["COL2"]); 
    if (di.ContainsKey(key)) 
    { 
     di[key].Add(dr); 
    } 
    else 
    { 
     di.Add(key, new List<DataRow>()); 
     di[key].Add(dr); 
    } 
} 

Interrogez le dictionnaire (plusieurs requêtes peut être nécessaire) pour filtrer les lignes et combiner les résultats dans une liste

string key1 = "VAL1//VAL2"; 
string key2 = "VAL1//<NULL>"; 
List<DataRow>() results = new List<DataRow>(); 
if (di.ContainsKey(key1)) 
{ 
    results.AddRange(di[key1]); 
} 
if (di.ContainsKey(key2)) 
{ 
    results.AddRange(di[key2]); 
} 
Questions connexes