Uwaga: Napisałem tę odpowiedź kiedy Entity Framework 4 była rzeczywista. Celem tej odpowiedzi nie było uzyskanie łatwego testu wydajności .Any()
vs .Count()
. Chodziło o to, by sygnalizować, że EF jest daleki od doskonałości. Nowsze wersje są lepsze ... ale jeśli masz część kodu, która jest wolna i używa EF, przetestuj z bezpośrednim TSQL i porównaj wydajność, zamiast polegać na założeniach (że .Any()
jest ZAWSZE szybszy niż .Count() > 0
).
Chociaż zgadzam się z najbardziej-głosowałem odpowiedź i komentarze - szczególnie na punkcie Any
sygnałów intencyjny deweloper lepiej niż Count() > 0
- miałem sytuację, w której hrabia jest szybsza o rząd wielkości na SQL Server (EntityFramework 4).
Oto zapytanie z Any
że thew Timeout wyjątku (na ~ 200,000 rekordy):
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
wersja wykonana w ciągu kilku milisekund:
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();
muszę znaleźć sposób, aby zobaczyć co dokładnie SQL oba LINQ produkują - ale jest oczywiste, że istnieje ogromna różnica wydajności między Count
i Any
w niektórych przypadkach, i niestety wydaje się, że nie można po prostu trzymać się z Any
we wszystkich przypadkach.
EDYCJA: Tutaj generowane są instrukcje SQL. Beauties jak widać;)
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
Wydaje się, że z czystym Gdzie ISTNIEJE działa znacznie gorsze niż obliczania policzyć i wtedy robi Gdzie z hrabiego == 0
Daj mi znać, jeśli zauważysz błąd w swoich ustaleniach. To, co można z tego wyrzucić bez względu na dyskusję Any vs Count, oznacza, że jakikolwiek bardziej złożony LINQ jest o wiele lepszy, gdy przepisywany jest jako procedura zapisana;).
Marc: ICollection w rzeczywistości nie pochodzi z ICollection. Ja też byłem zaskoczony, ale Reflector nie kłamie. –
Czy nie wykonuje kontroli Any() dla interfejsu ICollection i sprawdza po dla właściwości Count? – derigel
Nie, nie ma (po sprawdzeniu reflektora) –