Performance-Optimierung für Entity Framework Dr. Holger Schwichtenberg Softwarearchitekt, Berater, Trainer, Fachjournalist www.dotnet-doktor.de twitter.com/dotnetdoktor Version 8.2 Version 7.5.1 2.6 17.11.2015 / 22.09.2009 #1 15.06.2015 Kurze Vorstellung Dr. Holger Schwichtenberg Wirtschaftsinformatiker, Microsoft Most Valuable Professional (MVP) Entwicklungsleiter @ 5Minds IT Solutions GmbH & Co KG Dozent & Berater @ www.it-visions.de Autor für heise.de, ix, Windows Developer, dotnetpro, Hanser, O Reilly, Microsoft Press, Addison-Wesley, u.a. Blog & Twitter: www.dotnet-doktor.de Kontakt: buero@it-visions.de, 0201 649590-0 www.it-visions.de, Essen MVPs & Spezialisten für.net, Visual Studio, TFS, SQL Server, SharePoint, BizTalk, Windows Server, Azure, System Center, Xamarin, JavaScript, PowerShell, Java, Oracle, Agile, Scrum u.a. Strategische und technische Beratung Schulungen (individuell/in-house und standardisiert/öffentlich) 5Minds IT-Solutions GmbH & Co KG, Oberhausen Softwareentwicklung Ausleihe von Softwareentwicklern #16 1
Buch Moderne Datenzugriffslösungen mit Entity Framework 6 Ursprünglich in Arbeit für Microsoft Press jetzt verlegt bei Leanpub und Amazon https://leanpub.com/entityframework http://www.amazon.de/dp/b016on2tve #17 Agenda 1. EF oder nicht EF? EF 6 oder EF 7? 2. Profiling 3. LINQ-Befehlsreihenfolge 4. Ladestrategien 5. Caching 6. Paging und Virtualisierung 7. NoTracking/Detached Objects 8. Änderungsverfolgung optimieren 9. Stored Procedures vs. TVF 10. Massenoperationen Fazit ACHTUNG Nur 10 ausgewählte Themen im Schnelldurchgang. Eine Stunde reicht nicht, um alle Best Practices & Tipps ausführlich zu erörtern! #22 2
EF oder nicht EF? EF 6 oder EF 7? #36 Empfehlung Microsoft Quelle: http://nuget.org/packages/entityframework D.h. nicht, dass DataReader, Command und DataSet jetzt aus dem.net Framework 4.x verschwinden Aber für.net Core 5 ist kein DataSet mehr geplant!!! DataReader, Command, BulkInsert bleiben auch in.net 5 noch wichtige Instrumente für den Datenzugriff bei Massenoperationen und sehr großen Datenmengen Hybride Strategie #37 3
Vorgehensmodelle mit EF DB First (EF Designer) Model First (EF Designer) Code First ( "Code Based Modeling") EF-Versionen Bestehende Datenbank (Reverse Eng.) EF 1.0 bis 6.x Ja Nein EF 4.0 bis 6.x Nein Ja Seit EF 4.1 Ja (relativ neu) Ja Keine bestehende Datenbank (Forward Eng.) #38 Ziele der Neuimplementierung von EF in Version 7.0 Neuimplementierung, derzeit Beta 8 (15.10.2015) Einiges fehlt noch, derzeit noch langsamer als EF 6 in den meisten Fällen Geplantes Erscheinen: 1. Quartal 2016 Plattformneutral Läuft auf.net >4.5,.NET Core 5 und Mono >= 4.2.NET Core 5 / ASP.NET: Windows, Linux und MacOS.NET Core 5 / Windows 10 Universal Apps Mono/Xamarin: ios, Android Leichtgewichtiger: schneller & weniger RAM-Bedarf DBMS derzeit: SQL Server (inkl. Compact), SQLite, PostgreSql, InMemory Mittelfristig: Nicht-Relationale Datenspeicher (NoSQL) Einiges wird entfallen: DB & Modell First, EDMX, ObjectContext, Entity SQL Neue Features: Batch Updates, Default Values, LINQ-Verbesserungen, Kein Ziel: Kompatibilität zu EF 6.x / Kein Upgradetool von EF 6.x zu EF 7.x! EF 6.x wird auch noch weiterentwickelt. EF 6.2 geplant auch für das erste Quartal 2016 #40 4
Empfehlung EF 7 erstmal nur verwenden für ASP.NET 5 Mono demnächst auch Windows 10 UWP Apps http://blogs.msdn.com/b/adonet/archive/2015/10/15/ef7-beta-8-available.aspx: #41 Profiler für Entity Framework #42 5
Profiling Sehr wichtig. Wird zu oft vergessen Einfachste Protokollierung context.database.log = Console.WriteLine Externe Werkzeuge: Profiler des DBMS z.b. SQL Server Profiler Spezielle EF-Profiler #43 Demo: Entity Framework Profiler HibernatingRhinos http://efprof.com/ 389$ einmalig oder 287$ pro Jahr #45 6
Häufiger Fehler: Befehlsreihenfolge #55 Richtige Befehlsreihenfolge LINQ-to-Objects versus LINQ-to-Entities IEnumerable versus IQueryable var liste = query.tolist().where(x=>x.kategorie == 1) var liste = query.where(x=>x.kategorie == 1).ToList() var anz = query.count() var liste = query.tolist() var liste = query.tolist() var anz = liste.count() #56 7
Ladestrategien für abhängige Daten #58 EF-Ladestrategien Nicht kombinierbar mit NoTracking! #59 8
Demo: Lazy Loading vs. Eager Loading vs. Preloading #60 Daher geht Pre-Loading und daher ist Dispose() ist wichtig #61 9
Verfügbar seit Anzahl der ausgeführten SQL- Befehle Ausführungsdauer (ohne Ausgaben an der Konsole) Transparente s Lazy Loading Vergleich für 10.000 Flüge und 500 Piloten Explizites Lazy Loading ohne Prüfung des Cache Explizites Lazy Loading Eager Loading Pre-Loading / Relationship Fixup-Trick EF 4.0 EF 1.0 EF 1.0 EF 1.0 EF 1.0 501 10.001 501 1 2 3.5 53.3 Sekunden Sekunden Programmierstil Einfach Komplex, insbesondere Risiken Entwickler übersieht, dass er so viele SQL- Befehl ausführt und wundert sich über schlechte Leistung Entwickler vergisst ein Load() und bekommt keine Ergebnisse bzw. eine NullReference- Exception. Es werden unnötig Datensätze geladen, die sich schon im Zwischenspeicher befinden. 3.1 Sekunden 0.9 Sekunden Komplex Mittel Mittel Entwickler vergisst ein Load() und bekommt keine Ergebnisse bzw. eine NullReferenceException Man lädt ggf. Daten, die man vielleicht gar nicht braucht; der SQL- Befehl umfasst viele Joins und wird dadurch langsam. 0.7 Sekunden Man lädt ggf. Daten, die man vielleicht gar nicht braucht. Die verbundenen Daten sind möglicherweise nicht mehr aktuell. #62 Lazy Loading ist "tödlich" bei Serialisierung Bei Serialisierung führt automatisches Lazy Loading zu großen Objektgraphen, denn die Serializer greifen auf alle Properties zu Lösung: Automatisches Lazy Loading abschalten über ctx.contextoptions.lazyloadingenabled = false Tipp: Konfigurierbar machen in DAL/BL Ausnahme: System.Xml.Serialization.XmlSerializer serialisiert die Navigationsattribute nicht. #77 10
Caching #85 Caching First Level Caching Caching in der Kontextinstanz (vgl. Preloading-Trick!) System.Runtime.Caching (seit.net 4.0) Second Level Caching Bisher keine eingebaute Lösung (auch nicht in EF 7.0) EF Extended: FromCache(), FromCacheAsync(), FromCacheFirstOrDefault(), RemoveCache() https://www.nuget.org/packages/entityframework.extended https://github.com/loresoft/entityframework.extended #86 11
Second-Level-Caching #87 Demo: Caching #88 12
Paging und Virtualisierung #89 Paging und Virtualisierung Paging im DBMS: Lade nur Datensatz 500 bis 540 Alter Weg: rownumber()-funktion, TOP und einem Sub-Select Row Limiting Clauses Microsoft SQL Server ab Version 2012 (erschienen am 2.4.2012) Oracle bietet es seit Version 12c (erschienen am 1.7.2013). Nutzt EF leider erst ab Version 7.0 Paging im Entity Framework: Skip() und Take() UI Virtualization (verzögertes Rendering): in WPF eingebaut (DataGrid.EnableRowVirtualization, VirtualizingStackPanel.IsVirtualizing) Data Virtualization (verzögertes Datenabholen): nicht in WPF eingebaut, aber möglich http://www.codeproject.com/articles/34405/wpf-data-virtualization #91 13
#92 Demo: Paging und Virtualisierung in WPF #93 14
NoTracking (Abschalten des Change Tracking) #94 #99 15
Wie nutzt man No Tracking? Beim Entity Framework-Kontext für komplette Typen: Per LINQ-Abfrage durch Typkonvertierung auf ObjectQuery: AsNoTracking() seit EF 4.1 EF 7: NoTracking als Standard im Kontext einstellbar! #100 Trick: Nach NoTracking die "Detached"-Objekte dennoch zurückspeichern! Variante A: Attach() vor der Änderung Variante B: Attach() nach der Änderung #102 16
Demo: Eine DB aus einem realen Big-Data-Projekt Wie lange dauert es, ca. 280.000 Datensätze aus > 6 Milliarden (!!!) Datensätzen mit Entity Framework zu lesen im am besten programmierten Fall? #108 Änderungsverfolgung optimieren #123 17
Leistungsvergleich 500 Flug-Datensätze einfügen mit AddObject() bzw. Add() ctx.configuration. AutoDetectChangesEnabled = false AddRange() seit EF 6.0 #124 Ursache für Insert-Performance-Problem im DbContext EF sucht in POCO-Entitäten nach Änderungen (DetectChanges()) inkl. Relationship Fixup automatisch immer bei Find(), Local, Remove(), Add(), Attach(), GetValidationErrors(), Entry(), Entries() und SaveChanges() Wenn viele Entities im Kontext sind, kostet dies Zeit! DbContext mit AutoDetectChanges #127 18
Braucht man AutoDetectChanges überhaupt? Bei Add() nicht. Denn alle EF-API-Routinen setzen den Zustand korrekt. AutoDetectChanges stellt fest, ob sich außerhalb des EF-API das Objekt verändert hat. Hier wird nichts gespeichert, da EF das -- nicht merkt: ctx.configuration.autodetectchangesenabled = false f.freieplaetze-- ctx.savechanges() Sechs verschiedene Lösungen: 1. Change Tracking über Runtime Proxies machen 2. Vor Speichern AutoDetectChanges wieder einschalten 3. Vor Speichern muss man eine Methode aufrufen, die DetectChanges() auslöst, z.b. Add() im obigen Listing. 4. Verwende AddRange() zum Einfügen 5. Speichern ctx.changetracker.detectchanges() aufrufen 6. Alle Änderungen nur über EF-API: ctx.entry(f).property(p => p.freieplaetze).currentvalue -- #130 DetectChanges() Wird in EF 6.x hier aufgerufen: DbSet.Find DbSet.Local DbSet.Remove DbSet.Add DbSet.Attach DbContext.SaveChanges DbContext.GetValidationErrors DbContext.Entry DbChangeTracker.Entries In EF 7 nur noch hier: DbContext.SaveChanges DbSet.Local (o.ä. steht noch aus) DbContext.Entry DbChangeTracker.Entries #131 19
Table Valued Functions (Tabellenwertfunktion) #139 Was ist eine TVF? Im SQL Server seit Version 2000 https://www.nuget.org/packages/ EntityFramework. CodeFirstStoreFunctions Enthalten ab EF 7.0 #140 20
Demo: SP versus TVF #142 Leistung bei Massenoperationen #146 21
Tipp: Massenlöschen Lösche alle Flüge mit Flugnummer >200.000 Löschung mit Entity Framework/LINQ: Besser: Oder ganz klassisch: Alle laden, um sie zu löschen 25 ms 1255 ms Oder: Batch Delete/Updates in https://www.nuget.org/packages/entityframework.extended 25 ms 25 ms #151 Batch Update und Delete mit EntityFramework.Extended Batch Delete: SQL ist aber suboptimal: Batch Update: #153 22
Szenario 6: Masseneinfügen 1000x INSERT Wesentlich effizienter Siehe auch https://efbulkinsert.codeplex.com/ #155 Aus der Praxis Rechnen im RAM statt komplexe DB-Updates Der Kunde musste viele Datensätze in einer Zeitreihe aktualisieren. Hat das alles in DB gemacht. Komplexe Logik Verschachtelte SPs Dauer: mehrere Minuten im SQL Server Viel schneller: im RAM rechnen, in DB löschen und wieder einfügen! #156 23
Zusammenfassung #157 Fazit Entity Framework ist nicht langsam! Entity Framework ist natürlich (!) langsamer als ein DataReader Aber Entity Framework leistet auch viel mehr! Oder vergleichen Sie ein Amphibienfahrzeug mit einem Formel1- Auto? Es gibt viele Möglichkeiten, es falsch zu manchen mit Entity Framework Aber auch wenn Sie selbst Ihr SQL schreiben, können Sie viel falsch machen! Best-Practices-Vorgehensmodell: Im Regelfall EF einsetzen, dann optimieren, wo notwendig #160 24
Brauchen Sie Unterstützung? info@it-visions.de #161 Brauchen Sie Unterstützung? Architektur,.NET, HTML5, JavaScript, Apps, WinRT, SQL Server, SharePoint, Windows Server, BizTalk, CRM, u.v.a. Microsoft-Produkte sowie Oracle, MySQL, Ruby, Java Beratung bei Einführung, Migration und Betrieb (Vor-Ort-)Schulungen, Workshops Coaching (Vor-Ort Telefon E-Mail Online-Meeting) Support (Vor-Ort Telefon E-Mail Online-Meeting) Entwicklung von Prototypen und Lösung http://www.it-visions.de http://www.5minds.de Telefon 0201/649590-0 (Mo-Fr 9 bis 17) info@it-visions.de #162 25