Lazy Loading
Eintrag zuletzt aktualisiert am: 13.11.2023
Lazy Loading ist eine Optimierungstechnik, die hauptsächlich in bei Webanwendungen und bei
Objekt-Relationalen Mappern verwendet wird.
Lazy Loading bei Webanwendungen
Im Webentwicklungskontext bezieht sich Lazy Loading auf das Verzögern des Ladens von Ressourcen wie Bildern, Skripten oder anderen Dateien, bis der Benutzer sie tatsächlich benötigt oder auf sie zugreift. Dies kann die Ladezeiten von Webseiten erheblich verbessern, insbesondere wenn die Seite viele Ressourcen enthält, die nicht sofort sichtbar oder erforderlich sind.
Lazy Loading beim Objekt-Relationalen Mapping
Beim
Objekt-Relationalen Mapping bezieht sich Lazy Loading auf das Nachladen verbundener Datensätze, wenn diese benötigt werden. In vielen
Objekt-Relationalen Mapping wie z.B. Entity Framework und
Entity Framework Core bedeutet Lazy Loading das automatische Nachladen bei Bedarf. Eine entscheidende Frage für die Leistungsfähigkeit von ORM ist die Frage, wann verbundene
Objekte zu laden sind. Wenn man zu einem Flug sofort alle Buchungen und die dazugehörigen Passagier- und Personendaten lädt, lädt man unter Umständen mehr als wirklich gebraucht wird. Holt man die Daten jedoch nicht, müssen sie beim Zugriff auf eine
Objektreferenz nachgeladen werden. Das Nachladen bei Bedarf nennt man Lazy Loading, Deferred Loading oder Delayed Loading im Gegensatz zum
Eager Loading (alias Immediate Loading). Lazy Loading ist der Standard in allen ORM-Werkzeugen,
Eager Loading kann man auf Ebene einer Datenbankverbindung (alias Datenkontext oder Data Scope) oder einer einzelnen Anfrage steuern.
Lazy Loading beinhaltet eine besondere Herausforderung, denn das ORM-Werkzeug muss jeglichen Zugriff auf alle
Objektreferenzen »abfangen«, um hier bei Bedarf die verbundenen
Objekte nachladen zu können. Dieses Abfangen erfolgt durch die Verwendung bestimmter Klassen für Einzelreferenzen und Mengenklassen.
Der Einsatz von Lazy Loading mag auf den ersten Blick sehr komfortabel erscheinen, allerdings ist die Gefahr sehr groß, dass man sehr viele
SQL-Befehle zum
Datenbankmanagementsystem sendet ohne dies auf Anhieb zu erkennen. Der Autor dieses Beitrags wurde schon oft von Kunden zu Performance-Tuning-Einsätzen gerufen, wo sich der falsche Einsatz des Lazy Loading als ein Kernproblem entpuppte. Lazy Loading macht keinen Sinn, wenn man schon vorher weiß, dass alle Datensätze gebraucht werden. Hier sollte man
Eager Loading einsetzen.
Lazy Loading darf auf keinen Fall in Verbindung mit
Webservices,
Web-APIs/
REST-APIs,
RPC-Diensten und andere Szenarien verwendet werden, bei den die Entitätsobjekte in
Datenformate wie
SOAP,
XML,
JSON oder Protocol Buffers serialisiert werden. Die Serializer greifen auf alle Properties eines Entitätsobjekts zu und lösen dabei ein Lazy Loading aus. Somit werden unnötige
Objekte nachgeladen und mehr Daten als notwendig übertragen!
Die Wahl zwischen Lazy Loading und
Eager Loading ist oft auch die Wahl zwischen Pest und Cholera: Wenn man nicht genau weiß, ob die zusätzlichen Daten benötigt werden oder nicht, dann kann es ungünstig sein, sie direkt zu laden. Es kann aber auch ungünstig sein, sie später nachladen zu müssen. Wichtige Entscheidungskriterien sind:
- Wie wahrscheinlich ist, dass die Daten benötigt werden?
- Wie groß ist die Datenmenge?
- Kann ich überhaupt später die Daten einfach nachladen? (Wenn die Daten zwischenzeitlich serialisiert wurden, ist ein automatisches Nachladen in der Regel nicht mehr möglich!)
Beim klassischen Entity Framework ist Lazy Loading im Standard aktiv.
Bei
Entity Framework Core muss man Lazy Loading selbst erst aktivieren:
1. Lazy Loading via Runtime Proxies
Install-Package Microsoft.EntityFrameworkCore.Proxies
…
builder.UseLazyLoadingProxies().UseSqlServer(ConnectionString);
…
Alle Navigationseigenschaften im ganzen
Objektmodell müssen virtual sein.
2. Lazy Loading ohne
Proxyklassen
- Die Entitätsklasse muss darauf vorbereitet sein, eine ILazyLoader-Schnittstelle oder ILazyLoader.Load() als Delegate im Konstruktor injiziert zu bekommen. Letztes ist vorzuziehen, da ILazyLoader in der Microsoft.EntityFrameworkCore.dll steckt und damit eine Abhängigkeit des GO-Projekts mit den Entitätsklassen von Entity Framework Core erzwingen würde.
- In den Navigationseigenschaften muss dann Load() aufgerufen werden.