Entity Framework 4 – Generiertes SQL besser, aber nicht immer (Engpass TPT)
Während unserer Vorbereitungen auf die ORM Präsentation, habe ich für die Beispiele der Vererbungsstrategien Table per hierarchy (TPH), Table per type (TPT) und Table per conrete class (TPC) natürlich den SQL-Profiler laufen lassen.
Im Netz gibt es für die TPT-Strategie genügend Beispiele, die die Performanceschwachpunkte im Entity Framework darstellen. Die Zeitmessungen gehen dabei aber so gut wie gar nicht auf die Ressourcen ein, welche die Datenbank für sich beansprucht. Als Grund für die Wahl von TPT wird häufig auch die Ästhetik angeführt, weil diese sich wie OO anfühlt. Genau hier greift der ORM impedance mismatch und vermutlich die Folge des Versprechens, dass man mit ORM kein SQL beherrschen muss, darunter gehört auch wie ein RDBMS funktioniert.
Ein vernünftiges Argument für TPT ist bspw. die Releasetauglichkeit bei Standardlösungen, damit Individualerweiterungen den Kern der Anwendung nicht negativ beeinflussen.
Hinzu kommt zurzeit auch die Tatsache, dass das generierte SQL bei TPT suboptimal ist.
Aus diesem Grund bevorzuge ich, wenn möglich die TPH-Strategie, da diese bei Performanzüberlegungen die bessere Alternative darstellt. Auf dem Blog vom ADO.NET-Team gibt es zudem einen Blogbeitrag mit dem Versprechen, das generierte SQL für TPT zu verbessern, aber auch mit diesen Verbesserungen bleibt TPH für die Datenbank ressourcenschonender.
Bei TPH ist das generierte SQL gelegentlich redundant. Bezogen auf unserem Beispiel, haben wir folgende Vererbungshierarchie, die in der Datenbank innerhalb einer Tabelle gespeichert werden.
Dieses Beispiel existiert in den Formen TPH, TPT und TPC. In einen Test frage ich ab, wie viele Bücher existieren. Dafür erzeugt die folgende Linq-Abfrage:
C# (Linq)
using (var ctx = new ORMSamplesEntities())
{
var count = ctx.Products.OfType<Book>().Count();
Assert.AreEqual(2, count);
}
je nach Strategie folgende SQL-Abfragen
T-SQL bei TPH SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [TablePerHierarchie].[Product] AS [Extent1] WHERE ([Extent1].[ProductTypeNbr] IN ( CAST( '1' AS int), CAST( '2' AS int))) AND ([Extent1].[ProductTypeNbr] IN (1,2)) ) AS [GroupBy1]
In diesem Beispiel ist ersichtlich, dass die Diskriminator-Spalte 2 -mal gefiltert wird. Das ADO.NET – Team kann hier also auch noch Optimierungen vornehmen. ;-)
Bei TPT sieht das erzeugte SQL so aus:
T-SQL bei TPT SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM (SELECT [Extent1].[HardcoverId] AS [HardcoverId] FROM [TablePerType].[Hardcover] AS [Extent1] UNION ALL SELECT [Extent2].[EBookId] AS [EBookId] FROM [TablePerType].[EBook] AS [Extent2]) AS [UnionAll1] INNER JOIN [TablePerType].[Product] AS [Extent3] ON [UnionAll1].[HardcoverId] = [Extent3].[ProductId] INNER JOIN [TablePerType].[Book] AS [Extent4] ON [UnionAll1].[HardcoverId] = [Extent4].[BookId] ) AS [GroupBy1]
Das Ganze wird hier schon umfangreicher. Handgeschrieben würde ich in diesem Fall nur die Book-Tabelle abfragen und die Platzierung würde anders ausfallen.
Bei TPC wird hingegen folgendes SQL generiert:
T-SQL bei TPC SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM (SELECT 1 AS [C0] FROM [TablePerClass].[EBook] AS [Extent1] UNION ALL SELECT 1 AS [C0] FROM [TablePerClass].[Hardcover] AS [Extent2]) AS [UnionAll1] ) AS [GroupBy1]
Dieses SQL sieht, den Umständen entsprechend, verständlicher aus.
Bevor wir jetzt die Stoppuhr im Code ansetzen, wäre es zuerst mal interessant zu wissen, welche Ressourcen der Datenbankserver bei der jeweiligen Strategie benötigt, um diesen Faktor besser berücksichtigen zu können. Dafür stellen wir die 3 Abfragen gegenüber und lassen uns den Ausführungsplan anzeigen.
Das Ergebnis überrascht dann eigentlich nicht wirklich:
Welche Strategie bevorzugt nun unser Datenbankserver in diesem Szenario?
- Auf Platz 1 TPH (17%)
- Platz 2 TPC (33%)
- und auf Platz 3 TPT (50%)
Sollte jetzt die gewählte TPT-Strategie zu starken Performanzengpässen führen, dann wäre eine Migration - unter Berücksichtigung der Nachteile und Einbezug des DBA‘s - zu TPH denkbar. Auf das Entity-Modell würde es faktisch keine Auswirkungen haben.
- 0 Kommentar(e)




Mein Kommentar