2013-02-07 4 views
1

J'ai une requête LINQ qui s'exécute sur une base de données qui a 5 000 000 enregistrements en plus. Cette requête me renvoie une seule ligne mais prend presque 30 secondes à courir. Ceci est ma requêteRequête LINQ efficace pour un grand ensemble de données

var callDetailsForNodes = from records in dtRowForNode.Select().Select(dr => 
    new 
    { 
     caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F1"] : dr["F2"], 
     caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F2"] : dr["F1"], 
     time = dr["F3"], 
     filters = dr.Field<string>("F9") 
    }).Where(dr => (dtMin <= Convert.ToDateTime(dr.time)) && (dtMax >= Convert.ToDateTime(dr.time)) && (lstCallType.Contains(dr.filters)) 
      && (dtMinTime <= Convert.ToDateTime(dr.time).TimeOfDay) && (dtMaxTime >= Convert.ToDateTime(dr.time).TimeOfDay)) 
    .GroupBy(drg => new { drg.caller1, drg.caller2 }) 
    .Select(drg => new { drg.Key.caller1, drg.Key.caller2, count = drg.Count() }).AsEnumerable() 
            where (records.caller1.ToString() == VerSelected || records.caller2.ToString() == VerSelected) 
            select records; 

Encore une fois je lance une requête pour réorganiser les données ci-dessus obtiennent de requête comme

var callDetailsForNodes_ReArrange = from records in callDetailsForNodes.Select(r => new 
     { 
      caller1 = r.caller1.ToString() == VerSelected ? r.caller1 : r.caller2, 
      caller2 = r.caller1.ToString() != VerSelected ? r.caller1 : r.caller2, 
      count = r.count 
     }) 
     select records; 

alors je suis tout simplement se lier cette collection à gridview. est-il un moyen efficace d'interroger sur un vaste ensemble de données

Modifier

J'ai essayer de déboguer l'étape programm par étape et constater que ces 2 requêtes fonctionne réellement rapide et le temps est pris à l'étape quand j'ajoute le résultat de cette requête à ObservableCollection pour le lier à gridview. Voici le code

foreach (var callDetailsForNode_ReArrange in callDetailsForNodes_ReArrange) 
     { 

       _CallForNodes.Add(new CallForNodeData 
       { 
        Caller1 = callDetailsForNode_ReArrange.caller1.ToString(), 
        Caller2 = callDetailsForNode_ReArrange.caller2.ToString(), 
        Count = callDetailsForNode_ReArrange.count 
       }); 

     } 

Ici callDetailsForNodes_ReArrange a = nombre resultset 1

+1

_ "Existe-t-il un moyen efficace d'interroger un ensemble de données aussi important? _ Oui, utilisez une base de données! –

+0

Avez-vous cassé votre requête pour voir quelle partie est la plus lente? Par exemple. vous pouvez vous arrêter après votre premier 'Select' et appeler' ToList() '. Ensuite, ajoutez le 'Where' et appelez' ToList() 'etc. Cela vous aidera à identifier la partie qui ralentit le plus. Cependant, comme Tim dit que cela devrait être fait dans une base de données. –

+0

Je suppose que vous pouvez être confus. Une fois que vous commencez à parcourir la collection, elle exécute votre requête. 'callDetailsForNodes' est juste une requête jusqu'à ce que vous l'exécutiez. Ajouter 1 élément à un 'ObservableCollection' ne devrait pas être lent. –

Répondre

0

Une chose qui aide serait de convertir dTmin, Dtmax et dtMinTime avant l'appel dans les unités des données (dr.time) . Ensuite, vous pouvez vous débarrasser du Convert.ToDateTime qui se produit plusieurs fois sur chaque enregistrement.

+0

où devrais-je le faire, dans datatable lui-même ou au moment où je le récupère dans le code i.e time = Convert.ToDateTime (dr ["F3"]) –

+0

@RajeevKumar Ce que vous avez mis dans votre commentaire. – Rawling

+0

@RajeevKumar Dans votre première sélection, vous définissez 'time = dr [" F3 "]'. Je pense que Rawling suggère de changer cela en 'time = Convert.ToDateTime (dr [" F3 "])'. De cette façon 'time' est une date et n'a pas besoin d'être converti plusieurs fois dans' Where'. –

0

J'ai un peu réglé votre requête (bien que cela ne fasse pas une énorme différence de performance, et il peut y avoir des fautes de frappe car je n'ai pas VS à la main). De votre édition il semble que vous êtes un peu confus par l'exécution différée dans LINQ. callDetailsForNodes ne représente pas vos résultats - c'est une requête qui fournira vos résultats une fois qu'il est exécuté.

Si vous devez faire toutes ces requêtes en cours, je vous suggère d'ajouter un ToList après la première sélection et l'exécution de cette requête en isolation. Puis ajoutez ToList à la clause Where. L'appel ToList forcera votre requête à s'exécuter et vous verrez où les retards sont. Une note finale - vous devez transmettre directement vos enregistrements au constructeur ObservableCollection plutôt que d'appeler le Add pour chaque article. En appelant le Add, je ferai (je pense) que la collection déclenchera une notification modifiée, ce qui n'est pas une grosse affaire pour les petites listes, mais ralentira les choses pour les listes plus volumineuses.

var callDetailsForNodes = dtRowForNode.AsEnumerable() 
           .Select(dr => new { 
                caller1 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F1"] : dr["F2"], 
                caller2 = StringComparer.CurrentCultureIgnoreCase.Compare(dr["F1"], dr["F2"]) < 0 ? dr["F2"] : dr["F1"], 
                time = Convert.ToDateTime(dr["F3"]), 
                filters = dr.Field<string>("F9")}) 
           .Where(dr => (dtMin <= dr.time) 
             && (dtMax >= dr.time) 
             && (lstCallType.Contains(dr.filters)) 
             && (dtMinTime <= dr.time.TimeOfDay) 
             && (dtMaxTime >= dr.time.TimeOfDay) 
             && caller1 == VerSelected || caller2 == VerSelected)) 
           .GroupBy(drg => new { drg.caller1, drg.caller2 }) 
           .Select(drg => new { drg.Key.caller1, drg.Key.caller2, count = drg.Count()); 
Questions connexes