Nota: Ich habe diese Antwort geschrieben, als Entity Framework 4 aktuell war. Der Sinn dieser Antwort war es nicht, sich mit trivialen .Any()
vs .Count()
Leistungstests. Der Punkt war, zu signalisieren, dass EF weit davon entfernt ist, perfekt zu sein. 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 (die .Any()
ist IMMER schneller als .Count() > 0
).
Ich stimme mit den meisten Antworten und Kommentaren überein - insbesondere mit dem Punkt Any
Signale Entwicklerabsicht besser als Count() > 0
- Ich hatte eine Situation, in der Count auf SQL Server (EntityFramework 4) um eine Größenordnung schneller ist.
Hier ist die Abfrage mit Any
dass die Timeout-Ausnahme (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 wenigen 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, welche genaue SQL beide LINQs produzieren - aber es ist offensichtlich, es ist ein großer Leistungsunterschied zwischen Count
et Any
in einigen Fällen, und leider scheint es, dass man sich nicht einfach an die Any
in allen Fällen.
EDIT: Hier sind die generierten SQLs. Wunderschön, wie Sie sehen können ;)
ANY
:
exec sp\_executesql N'SELECT TOP (1)
\[Project2\].\[ContactId\] AS \[ContactId\],
\[Project2\].\[CompanyId\] AS \[CompanyId\],
\[Project2\].\[ContactName\] AS \[ContactName\],
\[Project2\].\[FullName\] AS \[FullName\],
\[Project2\].\[ContactStatusId\] AS \[ContactStatusId\],
\[Project2\].\[Created\] AS \[Created\]
FROM ( SELECT \[Project2\].\[ContactId\] AS \[ContactId\], \[Project2\].\[CompanyId\] AS \[CompanyId\], \[Project2\].\[ContactName\] AS \[ContactName\], \[Project2\].\[FullName\] AS \[FullName\], \[Project2\].\[ContactStatusId\] AS \[ContactStatusId\], \[Project2\].\[Created\] AS \[Created\], 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\],
\[Extent1\].\[Created\] AS \[Created\]
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\]
WHERE (\[Extent1\].\[ContactId\] = \[Extent2\].\[ContactId\]) AND (6 = \[Extent2\].\[NewsletterLogTypeId\])
))
) AS \[Project2\]
) AS \[Project2\]
WHERE \[Project2\].\[row\_number\] > 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\],
\[Project2\].\[ContactName\] AS \[ContactName\],
\[Project2\].\[FullName\] AS \[FullName\],
\[Project2\].\[ContactStatusId\] AS \[ContactStatusId\],
\[Project2\].\[Created\] AS \[Created\]
FROM ( SELECT \[Project2\].\[ContactId\] AS \[ContactId\], \[Project2\].\[CompanyId\] AS \[CompanyId\], \[Project2\].\[ContactName\] AS \[ContactName\], \[Project2\].\[FullName\] AS \[FullName\], \[Project2\].\[ContactStatusId\] AS \[ContactStatusId\], \[Project2\].\[Created\] AS \[Created\], row\_number() OVER (ORDER BY \[Project2\].\[ContactId\] ASC) AS \[row\_number\]
FROM ( SELECT
\[Project1\].\[ContactId\] AS \[ContactId\],
\[Project1\].\[CompanyId\] AS \[CompanyId\],
\[Project1\].\[ContactName\] AS \[ContactName\],
\[Project1\].\[FullName\] AS \[FullName\],
\[Project1\].\[ContactStatusId\] AS \[ContactStatusId\],
\[Project1\].\[Created\] AS \[Created\]
FROM ( SELECT
\[Extent1\].\[ContactId\] AS \[ContactId\],
\[Extent1\].\[CompanyId\] AS \[CompanyId\],
\[Extent1\].\[ContactName\] AS \[ContactName\],
\[Extent1\].\[FullName\] AS \[FullName\],
\[Extent1\].\[ContactStatusId\] AS \[ContactStatusId\],
\[Extent1\].\[Created\] AS \[Created\],
(SELECT
COUNT(1) AS \[A1\]
FROM \[dbo\].\[NewsletterLog\] AS \[Extent2\]
WHERE (\[Extent1\].\[ContactId\] = \[Extent2\].\[ContactId\]) AND (6 = \[Extent2\].\[NewsletterLogTypeId\])) AS \[C1\]
FROM \[dbo\].\[Contact\] AS \[Extent1\]
) AS \[Project1\]
WHERE (\[Project1\].\[CompanyId\] = @p\_\_linq\_\_0) AND (\[Project1\].\[ContactStatusId\] <= 3) AND (0 = \[Project1\].\[C1\])
) AS \[Project2\]
) AS \[Project2\]
WHERE \[Project2\].\[row\_number\] > 99
ORDER BY \[Project2\].\[ContactId\] ASC',N'@p\_\_linq\_\_0 int',@p\_\_linq\_\_0=4
Es scheint, dass reine Where mit EXISTS viel schlechter funktioniert als die Berechnung von Count und die anschließende Durchführung von Where mit Count == 0.
Lassen Sie mich wissen, wenn Sie Jungs sehen einige Fehler in meine Erkenntnisse. Was kann aus all dies unabhängig von Any vs Count Diskussion genommen werden ist, dass jede komplexere LINQ ist viel besser, wenn als Stored Procedure umgeschrieben;).