Entity Framework 4 – SQL-Optimierung mit Query Rewrite

Query Rewrite ist eigentlich eine Funktionalität von Oracle in Verbindung mit materialisierten Sichten. Mit dem SQL-Server funktioniert das in Verbindung mit indexierten Sichten nur, wenn die Enterprise- oder Developer-Version verwendet wird.

Die Funktionsweise ist denkbar einfach, wenn eine Anwendung Code mit vielen Joins an die Datenbank sendet, kann mit Hilfe einer materialsierten/indexierten Sicht diese optimiert werden. Der Vorteil dieses Features, es können Optimierungen vorgenommen werden, ohne den Code der zugrunde liegenden Applikation anpassen zu müssen.

Am Beispiel eines TPT-Szenarios probiere ich aus, wie sich Query Rewrite mit dem Entity Framework nutzen lässt. Dazu zuerst eine handgeschriebene SQL-Abfrage.

SQL 
SELECT     
	ProductTPT.Product.ProductId
	, ProductTPT.Product.Name
	, ProductTPT.Product.Description
	, ProductTPT.Book.ISBN10
	, ProductTPT.Book.ISBN13
	, ProductTPT.Book.LanguageCd
	, ProductTPT.Book.Pages
	, ProductTPT.EBook.EBookId
	, ProductTPT.EBook.Filename
FROM ProductTPT.Product 
INNER JOIN ProductTPT.Book ON ProductTPT.Product.ProductId = ProductTPT.Book.BookId 
INNER JOIN ProductTPT.EBook ON ProductTPT.Book.BookId = ProductTPT.EBook.EBookId

Bildlich gesehen stellt die Abfrage folgendes Modell dar.

Abbildung 1
Abbildung 1 Modell zum besseren Verständnis

Wenn die Abfrage ausgeführt wird, zeigt der Ausführungsplan den Ablauf in folgender Form:

Abbildung 2
Abbildung 2 Ausführungsplan der Join-Abfrage

Es kann Situationen geben, da führen Join-Abfragen aus der Anwendung heraus zu Performanzeinbussen. Bei Standard-Software besteht dann häufig das Problem, dass diese Abfragen innerhalb der Anwendung nicht optimiert werden können. Hier greift ein DBA häufig auf indexierte Sichten zurück.

Beim SQL-Server muss dazu eine Sicht mit Schemabinding und ein passender gruppierter Index angelegt werden.

SQL (Indexierte View)
CREATE VIEW [dbo].[vwEBook]
WITH SCHEMABINDING
AS
SELECT     
	ProductTPT.Product.ProductId
	, ProductTPT.Product.Name
	, ProductTPT.Product.Description
	, ProductTPT.Book.ISBN10
	, ProductTPT.Book.ISBN13
	, ProductTPT.Book.LanguageCd
	, ProductTPT.Book.Pages
	, ProductTPT.EBook.EBookId
	, ProductTPT.EBook.Filename
FROM ProductTPT.Product 
INNER JOIN ProductTPT.Book ON ProductTPT.Product.ProductId = ProductTPT.Book.BookId 
INNER JOIN ProductTPT.EBook ON ProductTPT.Book.BookId = ProductTPT.EBook.EBookId

Interessant bei dieser indexierten View ist der Abfrageplan, da gibt es nun nicht mehr viel zu sehen:

Abbildung 3
Abbildung 3 Abfrageplan der indexierten Sicht

Intern wird die Sicht wie eine Art Tabelle verwaltet, dadurch entfällt der Join-Aufwand. In der Enterprise- und Developer-Edition des SQL-Servers steht automatisch die "Query Rewrite" – Funktionalität zur Verfügung. Einfach gesagt, wenn der Optimizer merkt, dass eine Join-Abfrage mit einer passenden indexierten Sicht schneller abgearbeitet werden kann, dann wird ein "Query Rewrite" ausgeführt und stattdessen die indexierte Sicht verwendet.

Der folgende Ablaufplan verdeutlicht dies:

Abbildung 4
Abbildung 4 Veranschaulichung von Query Rewrite

Mit diesem Ausflug ist Query Rewrite erklärt. Es gibt aber auch Grenzen dieser Funktionalität, diese werden schnell bei Abfragen mit Inline-Views erreicht, so wie es das Entity Framework auch fabriziert. Betrachten wir nun, was für SQL das Entity Framework an die Datenbank sendet.

Die Abfrage in der Anwendung

C# (Linq-Abfrage)
var ebookList = ctx.Products.OfType<EBook>().ToList();

führt zu folgender SQL-Abfrage:

SQL (Entity Framework)
SELECT 
'0X0X0X' AS [C1], 
[Extent1].[EBookId] AS [EBookId], 
[Extent2].[Name] AS [Name], 
[Extent2].[Description] AS [Description], 
[Extent3].[ISBN10] AS [ISBN10], 
[Extent3].[ISBN13] AS [ISBN13], 
[Extent3].[LanguageCd] AS [LanguageCd], 
[Extent3].[Pages] AS [Pages], 
[Extent1].[Filename] AS [Filename]
FROM   [ProductTPT].[EBook] AS [Extent1]
INNER JOIN [ProductTPT].[Product] AS [Extent2] ON [Extent1].[EBookId] = [Extent2].[ProductId]
INNER JOIN [ProductTPT].[Book] AS [Extent3] ON [Extent1].[EBookId] = [Extent3].[BookId]

Der Unterschied ist nicht sehr gross, lediglich die Spalte C1 unterscheidet sich im groben und ganzen von den anderen Abfragen. Wenn wir diese im Ausführungsplan betrachten, ergibt sich dabei folgendes Bild:

Abbildung 5
Abbildung 5 Übersicht des Abfrageplans der 3 SQL-Statements (Manuell, Sicht, EF-SQL)

Der Unterschied, die Spalte C1 erzeugt zusätzlich einen Compute Scalar-Task, der jedoch keine Kosten verursacht. Der Optimizer merkt, dass er mit der indexierten Sicht die Anfrage viel schneller abarbeiten kann und verwendet diese.

Dieses Beispiel verdeutlicht, dass auch die Datenbank selbst gute Dienste bei der Optimierung leisten kann, sie müssen nur genutzt werden.

  •  
  • 0 Kommentar(e)
  •  

Mein Kommentar

Über jeden weiteren Kommentar in diesem Post benachrichtigen.

Zurück

Translate this page

Kategorien

  • [-].NET Development (215)
  • [-]Datenbank (26)
  • HTML (1)
  • Konfiguration (12)
  • Mind Map (10)
  • Off-topic (9)
  • Open Source (3)
  • Qualität (7)
  • Sharepoint (6)
  • Sicherheit (2)

Archiv

Social Bookmarking

Bookmark bei: Mr. Wong Bookmark bei: Webnews Bookmark bei: Icio Bookmark bei: Oneview Bookmark bei: Linkarena Bookmark bei: Favoriten Bookmark bei: Seekxl Bookmark bei: Favit Bookmark bei: Social Bookmarking Tool Bookmark bei: Power Oldie Bookmark bei: Bookmarks.cc Bookmark bei: Newskick Bookmark bei: Newsider Bookmark bei: Linksilo Bookmark bei: Readster Bookmark bei: Folkd Bookmark bei: Yigg Bookmark bei: Digg Bookmark bei: Del.icio.us Bookmark bei: Reddit Bookmark bei: Simpy Bookmark bei: StumbleUpon Bookmark bei: Slashdot Bookmark bei: Netscape Bookmark bei: Furl Bookmark bei: Yahoo Bookmark bei: Spurl Bookmark bei: Google Bookmark bei: Blinklist Bookmark bei: Blogmarks Bookmark bei: Diigo Bookmark bei: Technorati Bookmark bei: Newsvine Bookmark bei: Blinkbits Bookmark bei: Ma.Gnolia Bookmark bei: Smarking Bookmark bei: Netvouz Information