Hinweis: Ich habe diese Antwort geschrieben, als Entity Framework 4 aktuell war. Der Sinn dieser Antwort war nicht in trivial zu bekommen .Any()
vs .Count()
Performance - Tests. Es ging darum zu signalisieren, dass EF alles andere als perfekt ist. Neuere Versionen sind besser ... aber wenn Sie einen Teil des Codes haben, der langsam ist und EF verwendet, testen Sie mit direktem TSQL und vergleichen Sie die Leistung, anstatt sich auf Annahmen zu verlassen (das .Any()
ist IMMER schneller als .Count() > 0
).
Obwohl ich mit den meisten Antworten und Kommentaren einverstanden bin - insbesondere in Bezug auf den Punkt Any
, der die Absicht des Entwicklers besser signalisiert als Count() > 0
-, hatte ich eine Situation, in der Count auf SQL Server (EntityFramework 4) um eine Größenordnung schneller ist.
Hier ist eine Abfrage mit Any
dieser Ausnahme des Timeouts (bei ~ 200.000 Datensätzen):
con = db.Contacts.
Where(a => a.CompanyId == companyId && a.ContactStatusId <= (int) Const.ContactStatusEnum.Reactivated
&& !a.NewsletterLogs.Any(b => b.NewsletterLogTypeId == (int) Const.NewsletterLogTypeEnum.Unsubscr)
).OrderBy(a => a.ContactId).
Skip(position - 1).
Take(1).FirstOrDefault();
Count
Version in Millisekunden ausgeführt:
con = db.Contacts.
Where(a => a.CompanyId == companyId && a.ContactStatusId <= (int) Const.ContactStatusEnum.Reactivated
&& a.NewsletterLogs.Count(b => b.NewsletterLogTypeId == (int) Const.NewsletterLogTypeEnum.Unsubscr) == 0
).OrderBy(a => a.ContactId).
Skip(position - 1).
Take(1).FirstOrDefault();
Ich muss einen Weg finden, um zu sehen, welches genaue SQL beide LINQs produzieren - aber es ist offensichtlich, dass zwischen Count
und Any
in einigen Fällen ein großer Leistungsunterschied besteht , und leider scheint es, dass Sie nicht Any
in allen Fällen einfach bleiben können.
EDIT: Hier werden SQLs generiert. Schönheiten wie du sehen kannst;)
ANY
::
exec sp_executesql N'SELECT TOP (1)
[Project2]. [ContactId] AS [ContactId],
[Project2]. [CompanyId] AS [CompanyId],
[Projekt2]. [Kontaktname] AS [Kontaktname],
[Project2]. [FullName] AS [FullName],
[Project2]. [ContactStatusId] AS [ContactStatusId],
[Projekt2]. [Erstellt] AS [Erstellt]
FROM (SELECT [Project2]. [ContactId] AS [ContactId], [Project2]. [CompanyId] AS [CompanyId], [Project2]. [ContactName] AS [ContactName], [Project2]. [FullName] AS [FullName] , [Project2]. [ContactStatusId] AS [ContactStatusId], [Project2]. [Erstellt] AS [Erstellt], row_number () OVER (ORDER BY [Project2]. [ContactId] ASC) AS [row_number]
FROM (SELECT
[Extent1]. [ContactId] AS [ContactId],
[Extent1]. [CompanyId] AS [CompanyId],
[Extent1]. [ContactName] AS [ContactName],
[Extent1]. [FullName] AS [FullName],
[Extent1]. [ContactStatusId] AS [ContactStatusId],
[Umfang1]. [Erstellt] AS [Erstellt]
FROM [dbo]. [Contact] AS [Extent1]
WHERE ([Extent1]. [CompanyId] = @ p__linq__0) AND ([Extent1]. [ContactStatusId] <= 3) AND (NOT EXISTS (SELECT)
1 AS [C1]
FROM [dbo]. [NewsletterLog] AS [Extent2]
WO ([Extent1]. [ContactId] = [Extent2]. [ContactId]) UND (6 = [Extent2]. [NewsletterLogTypeId])
))
) AS [Projekt2]
) AS [Projekt2]
WO [Projekt2]. [Zeilennummer]> 99
ORDER BY [Project2]. [ContactId] ASC ', N' @ p__linq__0 int ', @ p__linq__0 = 4
COUNT
::
exec sp_executesql N'SELECT TOP (1)
[Project2]. [ContactId] AS [ContactId],
[Project2]. [CompanyId] AS [CompanyId],
[Projekt2]. [Kontaktname] AS [Kontaktname],
[Project2]. [FullName] AS [FullName],
[Project2]. [ContactStatusId] AS [ContactStatusId],
[Projekt2]. [Erstellt] AS [Erstellt]
FROM (SELECT [Project2]. [ContactId] AS [ContactId], [Project2]. [CompanyId] AS [CompanyId], [Project2]. [ContactName] AS [ContactName], [Project2]. [FullName] AS [FullName] , [Project2]. [ContactStatusId] AS [ContactStatusId], [Project2]. [Erstellt] AS [Erstellt], row_number () OVER (ORDER BY [Project2]. [ContactId] ASC) AS [row_number]
FROM (SELECT
[Projekt1]. [Kontakt-ID] AS [Kontakt-ID],
[Projekt1]. [CompanyId] AS [CompanyId],
[Projekt1]. [Kontaktname] AS [Kontaktname],
[Projekt1]. [Vollständiger Name] AS [Vollständiger Name],
[Projekt1]. [ContactStatusId] AS [ContactStatusId],
[Projekt1]. [Erstellt] AS [Erstellt]
FROM (SELECT
[Extent1]. [ContactId] AS [ContactId],
[Extent1]. [CompanyId] AS [CompanyId],
[Extent1]. [ContactName] AS [ContactName],
[Extent1]. [FullName] AS [FullName],
[Extent1]. [ContactStatusId] AS [ContactStatusId],
[Umfang1]. [Erstellt] AS [Erstellt],
(WÄHLEN
COUNT (1) AS [A1]
FROM [dbo]. [NewsletterLog] AS [Extent2]
WO ([Extent1]. [ContactId] = [Extent2]. [ContactId]) UND (6 = [Extent2]. [NewsletterLogTypeId])) AS [C1]
FROM [dbo]. [Contact] AS [Extent1]
) AS [Projekt1]
WHERE ([Project1]. [CompanyId] = @ p__linq__0) AND ([Project1]. [ContactStatusId] <= 3) AND (0 = [Project1]. [C1])
) AS [Projekt2]
) AS [Projekt2]
WO [Projekt2]. [Zeilennummer]> 99
ORDER BY [Project2]. [ContactId] ASC ', N' @ p__linq__0 int ', @ p__linq__0 = 4
Scheint, dass reines Where with EXISTS viel schlechter funktioniert als das Berechnen von Count und dann Where with Count == 0.
Lassen Sie mich wissen, wenn Sie einen Fehler in meinen Ergebnissen sehen. Was aus all dem herausgenommen werden kann, ist, dass komplexere LINQ viel besser dran sind, wenn sie als gespeicherte Prozedur umgeschrieben werden;).