2017-07-18 6 views
0

Ich mache ein Programm für eine Universität, die aktive Schüler ergreift und spuckt dann einen Bericht für andere Prozesse aus.Leistungsprobleme beim Ausführen von IQueryable.First()

Eine der wichtigen Funktionen ist es zu sehen, ob ein Student abgeschlossen ist oder nicht.

  • Wenn ein Student seinen Abschluss gemacht hat und nicht zurückkommt, gelten sie nicht als aktiver Student.
  • Wenn sie graduierten und kommen zurück oder nicht graduieren und kommen für ein weiteres Semester zurück, werden sie als aktiv angesehen.
  • Wenn ein Student die Hauptfunktion durchläuft, dauert es etwa 5 Sekunden, um den Prozess zu durchlaufen. Ich fand, dass die meiste Zeit, die Teil des Prozesses ist, von einem IQueryable.First() in dieser Funktion kommt.

    public static bool ContinuingEducation(string v) 
    { 
        var TERMSSTU = from t in _DB.TERMs 
             join stu in _DB.STUDENT_TERMS_VIEWs 
             on t.TERMS_ID equals stu.STTR_TERM 
             where v == stu.STTR_STUDENT 
             orderby t.TERM_START_DATE descending 
             select new { startdate = t.TERM_START_DATE }; 
        var graduation = from a in _DB.ACAD_CREDENTIALs 
             where v == a.ACAD_PERSON_ID 
             orderby a.ACAD_COMMENCEMENT_DATE ascending 
             select a; 
    
        if (graduation.Count() > 0 && TERMSSTU.Count() > 0) 
        { 
         if (TERMSSTU.First().startdate > graduation.First().ACAD_COMMENCEMENT_DATE) // the problem is here 
          return true; 
        } 
        return false; 
    } 
    

    Ich weiß nicht, warum es so lange hier dauert. Gibt es eine bessere Möglichkeit, diese Funktion zu schreiben, damit sie schneller ist?

    +3

    Sie führen 4 Abfragen aus. 2 für die Zählung und dann 2 weitere, um die erste Zeile jeder Abfrage zu erhalten. Verwenden Sie stattdessen "FirstOrDefault" und prüfen Sie, ob die Ergebnisse "null" sind, um festzustellen, ob es mehr als einen gibt. – juharr

    +0

    Haben Sie Ihr Problem Franco gelöst? – mjwills

    +0

    Ich postete meine Lösung unten –

    Antwort

    0

    Meine beste Wette zu bekommen einige ernsthafte Effizienz die Datensätze am Anfang meines Programms, so dass alle Datensätze sind im Speicher abzufragen war, die eine Brise für das Programm gemacht abfragt.

    1. Ich habe eine neue Klasse, die diese beiden Abfragen

      public class TERMSTU { public Datetime erfasst? Startdatum {get; einstellen; } öffentliche String-ID {get; einstellen; } }

      öffentliche Klasse Graduation { public DateTime?ACAD_COMMENCEMENT_DATE {erhalten; einstellen; } öffentliche String-ID {get; einstellen; } } public class Bericht { private Liste TERMSSTUS; private Liste GRADUATIONEN; öffentlichen Report (ColleagueDataContext _DB) { var TERMSSTU = von t in _DB.TERMs stu kommen in _DB.STUDENT_TERMS_VIEWs auf t.TERMS_ID gleich stu.STTR_TERM orderby t.TERM_START_DATE absteigend neue Option {startdate = t.TERM_START_DATE , id = stu.STTR_STUDENT}; TERMSSTUS = neue Liste(); foreach (var i in TERMSSTU) { TERMSSTUS.Add (neue TERMSTU() {Id = i.id, Startdatum = i.startdate}); }

      var graduation = from a in _DB.ACAD_CREDENTIALs 
              where a.ACAD_COMMENCEMENT_DATE != null 
              where a.ACAD_COMMENCEMENT_DATE < DateTime.Today 
              orderby a.ACAD_COMMENCEMENT_DATE descending 
              select a; 
      
          GRADUATIONS = new List<Graduation>(); 
          foreach (var i in graduation) 
          { 
           GRADUATIONS.Add(new Graduation() { Id = i.ACAD_PERSON_ID, ACAD_COMMENCEMENT_DATE = i.ACAD_COMMENCEMENT_DATE }); 
          } 
      } 
      public List<TERMSTU> givestu() 
      { 
          return TERMSSTUS; 
      } 
      public List<Graduation> givegrad() 
      { 
          return GRADUATIONS; 
      } 
      

      }

    2. modifizierte ich die Funktion zu ergreifen, um die beiden Abfragen

      public static bool ContinuingEducation(string v, List<TERMSTU> t, List<Graduation> g) 
      { 
          var term = (from stu in t where stu.Id == v select stu).FirstOrDefault(); 
          var grad = (from gradu in g where gradu.Id == v select gradu).FirstOrDefault(); 
          return term.startdate > grad.ACAD_COMMENCEMENT_DATE.Value.AddDays(-14); 
      } 
      

    Diese Methode mehr Code hat zu schreiben, aber es spart Zut Zeit wenn das Programm 3000 Datensätze durchlaufen muss.

    +0

    Hat jeder 'stu' eine eindeutige' Id'? Hat jeder "gradu" eine eindeutige "Id"? Wenn dies der Fall ist, sollten Sie sie in einem 'Dictionary' anstatt in einer' List' speichern, um eine ** dramatische ** Geschwindigkeit zu erzielen. – mjwills

    +0

    In Ihrer "ContinuingEducation" -Methode sollten Sie auch überlegen, was Ihr Code tun soll, wenn entweder 'term' oder' grad' null ist. Der Code wird eine Ausnahme auslösen. – mjwills

    +0

    Ich werde es versuchen. Ich halte euch auf dem Laufenden –

    4

    Ihre Nutzung von Count ist ineffizient, da Sie die Datenbank zusätzliche Zeiten abfragen müssen (einmal die Count zu bekommen, sobald die First zu bekommen). Die folgende Codeänderung wird die Notwendigkeit entfernen, die Count zu erhalten.

    Wechsel:

    if (graduation.Count() > 0 && TERMSSTU.Count() > 0) 
    { 
        if (TERMSSTU.First().startdate > graduation.First().ACAD_COMMENCEMENT_DATE) // the problem is here 
         return true; 
    } 
    return false; 
    

    zu:

    var grad = graduation.FirstOrDefault(); 
    var term = TERMSSTU.FirstOrDefault() 
    
    if (grad == null || term == null) 
        return false; 
    
    return term.startdate > grad.ACAD_COMMENCEMENT_DATE; 
    

    Beachten Sie, dass auch nach dieser Änderung wird die FirstOrDefault wahrscheinlich immer noch langsam. Um dies zu beheben, sollten Sie eine SQL Trace ausführen, um zu sehen, was SQL generiert wird. Dann schauen Sie auf add indexes/optimieren Sie die Abfrage.

    +1

    Hinzufügen zu dieser Antwort: der Grund, warum die 'First' ist langsam im Vergleich zu den' Count' ist, dass die 'First' muss die' Reihenfolge von' ausführen, um sicherzustellen, dass es die erste erhält Element basierend auf der Reihenfolge. – Maxime

    0

    Das Leistungsproblem ist nicht in First Anruf aber in Ihrer Abfrage. Es wird ausgewertet, wenn Sie First aufrufen.

    Sie sollten Code neu schreiben, um weniger Abfragen zu verwenden: Eq können Sie beide Abfragen auf dem Parameter v beitreten und dann das Ergebnis abrufen und seine Daten überprüfen. Es wird zu einer einzelnen Abfrage führen.

    2

    Try-Code

    public static bool ContinuingEducation(string v) 
    { 
        var TERMSSTU = (from t in _DB.TERMs.AsQueryable() 
            join stu in _DB.STUDENT_TERMS_VIEWs.AsQueryable() 
            on t.TERMS_ID equals stu.STTR_TERM 
            where v == stu.STTR_STUDENT 
            orderby t.TERM_START_DATE descending 
            select new { startdate = t.TERM_START_DATE }).FirstOrDefault(); 
        var graduation = (from a in _DB.ACAD_CREDENTIALs.AsQueryable() 
            where v == a.ACAD_PERSON_ID 
            orderby a.ACAD_COMMENCEMENT_DATE ascending 
            select a).FirstOrDefault(); 
    
        if (graduation==null || TERMSSTU==null) 
         return false; 
    
        return TERMSSTU.startdate >graduation.ACAD_COMMENCEMENT_DATE; 
    }