Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Linq: Include Performance-Frage
andreas-82
myCSharp.de - Member

Avatar #avatar-2724.gif


Dabei seit:
Beiträge: 43
Herkunft: Bocholt

Themenstarter:

Linq: Include Performance-Frage

beantworten | zitieren | melden

verwendetes Datenbanksystem: EntityFramework 4 / SqlServer2008

Hallo zusammen!
Ich arbeite mich gerade in Linq-Abfragen gegen ein EF4-Model ein und bin
beim Untersuchen verschiedener Queries mit dem Sql Profiler auf eine Frage gestoßen:

Es geht um eine einfache Kontakte - Adressen - Abfrage.
Die Frage ist, wenn ich in der Abfrage per 'Include' die Adressen mitlade, warum kann ich dann nicht über ein Select nur bestimmt Spalten des Contact-Entities laden? Sobald Include verwendet wird, werden immer auch alle Spalten vom Contact-Entity geladen

var result = from c in context.Contacts.Include("Addresses")
                     select new { c.LastName, c.ContactID, c.Addresses};

SQL-Profiler:
SELECT 
[Project1].[ContactID] AS [ContactID], 
[Project1].[LastName] AS [LastName], 
[Project1].[FirstName] AS [FirstName], 
[Project1].[Title] AS [Title], 
[Project1].[AddDate] AS [AddDate], 
[Project1].[ModifiedDate] AS [ModifiedDate], 
[Project1].[C1] AS [C1], 
[Project1].[addressID] AS [addressID], 
[Project1].[Street1] AS [Street1], 
[Project1].[Street2] AS [Street2], 
[Project1].[City] AS [City], 
[Project1].[StateProvince] AS [StateProvince], 
[Project1].[CountryRegion] AS [CountryRegion], 
[Project1].[PostalCode] AS [PostalCode], 
[Project1].[AddressType] AS [AddressType], 
[Project1].[ContactID1] AS [ContactID1], 
[Project1].[ModifiedDate1] AS [ModifiedDate1]
FROM ( SELECT 
	[Extent1].[ContactID] AS [ContactID], 
	[Extent1].[FirstName] AS [FirstName], 
	[Extent1].[LastName] AS [LastName], 
	[Extent1].[Title] AS [Title], 
	[Extent1].[AddDate] AS [AddDate], 
	[Extent1].[ModifiedDate] AS [ModifiedDate], 
	[Extent2].[addressID] AS [addressID], 
	[Extent2].[Street1] AS [Street1], 
	[Extent2].[Street2] AS [Street2], 
	[Extent2].[City] AS [City], 
	[Extent2].[StateProvince] AS [StateProvince], 
	[Extent2].[CountryRegion] AS [CountryRegion], 
	[Extent2].[PostalCode] AS [PostalCode], 
	[Extent2].[AddressType] AS [AddressType], 
	[Extent2].[ContactID] AS [ContactID1], 
	[Extent2].[ModifiedDate] AS [ModifiedDate1], 
	CASE WHEN ([Extent2].[addressID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
	FROM  [dbo].[Contact] AS [Extent1]
	LEFT OUTER JOIN [dbo].[Address] AS [Extent2] ON [Extent1].[ContactID] = [Extent2].[ContactID]
)  AS [Project1]
ORDER BY [Project1].[ContactID] ASC, [Project1].[C1] ASC
Macht sich das in der Performance nicht ab einer bestimmten Zeilen- und Spaltenanzahl bemerkbar, wenn einfach immer alle Spalten geladen werden?
Lässt sich dies mit Include überhaupt einschränken?
Ist es hier alternativ besser ein Nested-Query zu verwenden?

Vielen Dank schon mal für Ideen :)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von andreas-82 am .
~ There's no knowledge that is not power~
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10083

beantworten | zitieren | melden

Wenn du nicht viele (N)VarChar(MAX) Felder hast, ist die Perfomrmance nur dann betroffen, wenn du wirklich viele Spalten hast.
Und viele Spalten in einer Tabelle deuten meist auf suboptimale Normalisierung hin.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16145

beantworten | zitieren | melden

Hi,

rein theoretisch ist es mit dem EF kein Problem nur bestimmte Spalten zu laden - eben durch

select new {...}
Ich vermute aber, dass Du Deine Entitäten mit dem GUI Designer angelegt hast, in dessen Schema definiert ist, welche Spalten geladen werden - nämlich alle.
Gruß
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Abt am .
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Ahrimaan
myCSharp.de - Member



Dabei seit:
Beiträge: 363
Herkunft: Thorn

beantworten | zitieren | melden

Vll hilft dir das auch etwas bei der Performance (Lazy Loading)
Klick Mich

Grüße
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Zitat von Abt
rein theoretisch ist es mit dem EF kein Problem nur bestimmte Spalten zu laden - eben durch

select new {...}
Hi,

so allgemein formuliert ist es nicht richtig. Wenn er Objektgraphen mit Include() erzeugen will _muß_ das Root-Entity vollständig sein. War zumindest in EF1 so. Wenn er nur "Daten aus einer einzelnen Tabelle" benötigt kann er mit anonymen Objekten / EntityDataReader arbeiten.
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Zitat von andreas-82
vMacht sich das in der Performance nicht ab einer bestimmten Zeilen- und Spaltenanzahl bemerkbar, wenn einfach immer alle Spalten geladen werden?
Ich habe in einer App alle 5000 Patienten aller Stationen aller Krankenhäuser eines Trägers geladen, das Übertragen der Daten und deren Materialisierung hat 2 sec gedauert. Ich würde vorschlagen dass Du mit Deiner Lösung weitermachst und erst optimierst wenn Probleme auftauchen.
private Nachricht | Beiträge des Benutzers
andreas-82
myCSharp.de - Member

Avatar #avatar-2724.gif


Dabei seit:
Beiträge: 43
Herkunft: Bocholt

Themenstarter:

beantworten | zitieren | melden

Danke schon mal für eure Antworten.
Zitat von Ahrimaan
Vll hilft dir das auch etwas bei der Performance (Lazy Loading)
Klick Mich
Lazy Loading steht auf false.
In meinem (Lern)Beispiel wollte ich mich mit eager loading auseinandersetzen.
Zitat von witte
...so allgemein formuliert ist es nicht richtig. Wenn er Objektgraphen mit Include() erzeugen will _muß_ das Root-Entity vollständig sein. War zumindest in EF1 so. Wenn er nur "Daten aus einer einzelnen Tabelle" benötigt kann er mit anonymen Objekten / EntityDataReader arbeiten.
Das ist ja das was mich wundert, dass sobald ich ein include setze, dass Root-Entity vollständig zurückgegeben wird.
Wenn ich anstelle des Includes ein Nested Querie verwende, werden auch im Root-Entity nur die im Select-Block angegebenen Spalten ausgelesen:

var result = from c in context.Contacts.Include("Addresses")
                     select new { c.LastName,
                                  c.ContactID, 
                                  City = ((from a in c.Addresses 
                                           where a.ContactID == c.ContactID 
                                           select a.City).FirstOrDefault()) };

SQL-Profiler:
SELECT 
[Extent1].[ContactID] AS [ContactID], 
[Extent1].[LastName] AS [LastName], 
(SELECT TOP (1) 
	[Extent2].[City] AS [City]
	FROM [dbo].[Address] AS [Extent2]
	WHERE ([Extent1].[ContactID] = [Extent2].[ContactID]) AND ([Extent2].[ContactID] = [Extent1].[ContactID])) AS [C1]
FROM [dbo].[Contact] AS [Extent1]
Zitat von witte
Ich habe in einer App alle 5000 Patienten aller Stationen aller Krankenhäuser eines Trägers geladen, das Übertragen der Daten und deren Materialisierung hat 2 sec gedauert. Ich würde vorschlagen dass Du mit Deiner Lösung weitermachst und erst optimierst wenn Probleme auftauchen.
Prinzipiell hast du recht - auch wenn ich alles immer so perfekt wie möglich machen möchte - ich denke die Geschwindigkeitsunterschiede wird man auch bei mehreren Datensätzen nicht merken.
Wundern tut mich die Sache jedoch trotzdem noch ;(
~ There's no knowledge that is not power~
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Hi,
Zitat von andreas-82
Das ist ja das was mich wundert, dass sobald ich ein include setze, dass Root-Entity vollständig zurückgegeben wird.
Ein ORM hat nunmal die Aufgabe dem Client die Illusion eines unendlichen, nichtflüchtigen Workspace seiner Objekte zu geben. Du willst -so hast Du es modelliert- genau diese Objekte haben und nicht nur mit Fragmenten arbeiten.
Wenn Du Enitities z.B. für Reporting "shapen" willst dann nimm doch diese nested queries oder die Join-Syntax.
Wenn Du es verwenden willst um beispielsweise ein teures Memofeld auszublenden was Du jetzt nicht benötigst, wird es schwierig, da Property-LazyLoading nicht unterstützt wird. Möglicherweise hilft vertikale Partitionierung der Entities oder Vererbung mit TablePerHierarchy.
Zitat von andreas-82
Wenn ich anstelle des Includes ein Nested Querie verwende, werden auch im Root-Entity nur die im Select-Block angegebenen Spalten ausgelesen:
Mag sein, aber die Daten sind dann nicht mehr aktualisierbar.
private Nachricht | Beiträge des Benutzers