2016-03-09 9 views
6

Ho circa 250.000 record contrassegnati come Boss, ogni Boss ha da 2 a 10 dipendenti. Ogni giorno ho bisogno di ottenere i dettagli dello Staff. Circa ci sono 1.000.000 di personale. Sto usando Linq per ottenere l'elenco Unico di Staff che viene lavorato quotidianamente. Si consideri il seguente C# LINQ e ModelleCome usare Efficiently Where Clausola o Seleziona in LINQ Parallel in Large Dataset

void Main() 
{ 

    List<Boss> BossList = new List<Boss>() 
    { 
     new Boss() 
     { 
      EmpID = 101, 
      Name = "Harry", 
      Department = "Development", 
      Gender = "Male", 
      Employees = new List<Person>() 
      { 
       new Person() {EmpID = 102, Name = "Peter", Department = "Development",Gender = "Male"}, 
       new Person() {EmpID = 103, Name = "Emma Watson", Department = "Development",Gender = "Female"}, 

      } 
     }, 
     new Boss() 
     { 
      EmpID = 104, 
      Name = "Raj", 
      Department = "Development", 
      Gender = "Male", 
      Employees = new List<Person>() 
        { 
         new Person() {EmpID = 105, Name = "Kaliya", Department = "Development",Gender = "Male"}, 
         new Person() {EmpID = 103, Name = "Emma Watson", Department = "Development",Gender = "Female"}, 

        } 
     }, 

     ..... ~ 250,000 Records ...... 

    }; 

    List<Person> staffList = BossList 
    .SelectMany(x => 
     new[] { new Person { Name = x.Name, Department = x.Department, Gender = x.Gender, EmpID = x.EmpID } } 
     .Concat(x.Employees)) 
    .GroupBy(x => x.EmpID) //Group by employee ID 
    .Select(g => g.First()) //And select a single instance for each unique employee 
    .ToList(); 
} 

public class Person 
{ 
    public int EmpID { get; set; } 
    public string Name { get; set; } 
    public string Department { get; set; } 
    public string Gender { get; set; } 
} 

public class Boss 
{ 
    public int EmpID { get; set; } 
    public string Name { get; set; } 
    public string Department { get; set; } 
    public string Gender { get; set; } 
    public List<Person> Employees { get; set; } 
} 

Nel LINQ sopra sto ottenendo l'elenco dei dipendenti distinti o il personale, l'elenco contiene più di 1.000.000 di record. Dalla lista ottenuta ho bisogno di cercare "Raj"

staffList.Where(m => m.Name.ToLowerInvariant().Contains("Raj".ToLowerInvariant())); 

Per questa operazione, ci sono voluti più di 3 a 5 minuti per ottenere il risultato.

Come potrei renderlo più efficiente. Gentilmente assistermi ...

+0

Qual è l'obiettivo qui? Perché hai bisogno di ottenere tanti record per trovare 'raj'? –

+1

Nel mio vero progetto ci sono così tante proprietà che ci sono in Person Model, ad esempio LedgerAccounts, NoOfDaysPresent, ecc., Se Raj si avvicina e chiede la presenza, ora ho bisogno di recuperare il record di Raj ... –

+0

Ok. Quindi "Raj" è il capo? e stai cercando di ottenere la partecipazione dei suoi subordinati? –

risposta

0

Potrebbe funzionare per voi cambiare la lista del personale in un dizionario? Un algoritmo di ricerca migliore come quelli di Dictionary e SortedList ti darebbe il massimo miglioramento.

Ho testato il codice qui sotto e funziona in pochi secondi.

private static void Main() 
    { 

     List<Boss> BossList = new List<Boss>(); 
     var b1 = new Boss() 
     { 
      EmpID = 101, 
      Name = "Harry", 
      Department = "Development", 
      Gender = "Male", 
      Employees = new List<Person>() 
      { 
       new Person() {EmpID = 102, Name = "Peter", Department = "Development", Gender = "Male"}, 
       new Person() {EmpID = 103, Name = "Emma Watson", Department = "Development", Gender = "Female"}, 

      } 
     }; 

     var b2 = new Boss() 
     { 
      EmpID = 104, 
      Name = "Raj", 
      Department = "Development", 
      Gender = "Male", 
      Employees = new List<Person>() 
      { 
       new Person() {EmpID = 105, Name = "Kaliya", Department = "Development", Gender = "Male"}, 
       new Person() {EmpID = 103, Name = "Emma Watson", Department = "Development", Gender = "Female"}, 

      } 
     }; 

     Random r = new Random(); 
     var genders = new [] {"Male", "Female"}; 

     for (int i = 0; i < 1500000; i++) 
     { 
      b1.Employees.Add(new Person { Name = "Name" + i, Department = "Department" + i, Gender = genders[r.Next(0, 1)], EmpID = 200 + i }); 
      b2.Employees.Add(new Person { Name = "Nam" + i, Department = "Department" + i, Gender = genders[r.Next(0, 1)], EmpID = 1000201 + i }); 
     } 

     BossList.Add(b1); 
     BossList.Add(b2); 

     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 

     var emps = BossList 
      .SelectMany(x => 
       new[] {new Person {Name = x.Name, Department = x.Department, Gender = x.Gender, EmpID = x.EmpID}} 
        .Concat(x.Employees)) 
      .GroupBy(x => x.EmpID) //Group by employee ID 
      .Select(g => g.First()); 

     var staffList = emps.ToList(); 
     var staffDict = emps.ToDictionary(p => p.Name.ToLowerInvariant() + p.EmpID); 
     var staffSortedList = new SortedList<string, Person>(staffDict); 

     Console.WriteLine("Time to load staffList = " + sw.ElapsedMilliseconds + "ms"); 

     var rajKeyText = "Raj".ToLowerInvariant(); 
     sw.Reset(); 
     sw.Start(); 

     var rajs1 = staffList.AsParallel().Where(p => p.Name.ToLowerInvariant().Contains(rajKeyText)).ToList(); 
     Console.WriteLine("Time to find Raj = " + sw.ElapsedMilliseconds + "ms"); 

     sw.Reset(); 
     sw.Start(); 

     var rajs2 = staffDict.AsParallel().Where(kvp => kvp.Key.Contains(rajKeyText)).ToList(); 
     Console.WriteLine("Time to find Raj = " + sw.ElapsedMilliseconds + "ms"); 

     sw.Reset(); 
     sw.Start(); 

     var rajs3 = staffSortedList.AsParallel().Where(kvp => kvp.Key.Contains(rajKeyText)).ToList(); 
     Console.WriteLine("Time to find Raj = " + sw.ElapsedMilliseconds + "ms"); 

     Console.ReadLine(); 
    } 

    public class Person 
    { 
     public int EmpID { get; set; } 
     public string Name { get; set; } 
     public string Department { get; set; } 
     public string Gender { get; set; } 
    } 

    public class Boss 
    { 
     public int EmpID { get; set; } 
     public string Name { get; set; } 
     public string Department { get; set; } 
     public string Gender { get; set; } 
     public List<Person> Employees { get; set; } 
    } 
} 

Output1:

enter image description here

Output2 (usando .AsParallel() sulle ricerche):

enter image description here

In altre parole, se non è possibile utilizzare alcuni più veloce la struttura dei dati può accelerare la ricerca semplicemente cambiando il modulo

staffList.Where(m => m.Name.ToLowerInvariant().Contains("Raj".ToLowerInvariant())); 

a

staffList.AsParallel().Where(m => m.Name.ToLowerInvariant().Contains("Raj".ToLowerInvariant())); 
+0

No, qui sto usando la casella di testo di ricerca basata sul testo di ricerca, restituisce il risultato. Non inserisco il nome esatto ... Questo è il problema ... –

+0

Ho apportato alcune modifiche per confrontare le prestazioni. Inoltre, perché non puoi usare Dictionary o SortedList? Vuoi trovare tutti i dipendenti in cui il loro nome contiene una sottostringa, giusto? Non otterrai la ricerca O (1), ma sarà più veloce della ricerca della lista. – EduardoCMB

+0

Grazie per il tuo tempo speso. Il dizionario può verificare se la chiave esiste o no. Se la chiave esiste, possiamo ottenere il risultato. Qui nutro solo il testo grezzo. Allora come potrebbe restituire il risultato? stai controllando kvp.Key.Contains (rajKeyText) la frase esatta di Key ... Qui non è possibile. Perché ci sarà più di un Raj ... –

Problemi correlati