Примечание: я написал этот ответ, когда Entity Framework 4 был актуален. Смысл этого ответа не состоял в том, чтобы войти в тривиальное по .Any()
сравнению с .Count()
тестированием производительности. Смысл в том, чтобы сигнализировать, что EF далека от совершенства. Новые версии лучше ... но если у вас есть часть кода, которая работает медленно и использует EF, протестируйте с прямым TSQL и сравните производительность, а не полагайтесь на предположения (что .Any()
ВСЕГДА быстрее, чем .Count() > 0
).
Хотя я согласен с большинством ответов и комментариев, за которые проголосовали, особенно если речь идет о намерениях разработчиков точныхAny
сигналов лучше, чем у меня, я столкнулся с ситуацией, когда на SQL Server счетчик работает на порядок быстрее (EntityFramework 4).Count() > 0
Вот запрос с Any
этим исключением тайм-аута (на ~ 200.000 записей):
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
Версия выполняется за считанные миллисекунды:
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();
Мне нужно найти способ посмотреть, какой именно SQL выдают оба LINQ - но очевидно, что существует огромная разница в производительности между Count
и Any
в некоторых случаях, и, к сожалению, кажется, что вы не можете просто придерживаться Any
во всех случаях.
РЕДАКТИРОВАТЬ: Здесь генерируются SQL. Красавицы как видите;)
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]
ОТ (ВЫБЕРИТЕ [Project2]. [ContactId] AS [ContactId], [Project2]. [CompanyId] AS [CompanyId], [Project2]. [ContactName] AS [ContactName], [Project2]. [FullName] AS [FullName] , [Project2]. [ContactStatusId] AS [ContactStatusId], [Project2]. [Создано] AS [Создано], row_number () OVER (ORDER BY [Project2]. [ContactId] ASC) AS [row_number]
ОТ (ВЫБРАТЬ
[Extent1]. [ContactId] AS [ContactId],
[Extent1]. [CompanyId] AS [CompanyId],
[Extent1]. [ContactName] AS [ContactName],
[Extent1]. [FullName] AS [FullName],
[Extent1]. [ContactStatusId] AS [ContactStatusId],
[Extent1]. [Создано] AS [Создано]
FROM [dbo]. [Contact] AS [Extent1]
ГДЕ ([Extent1]. [CompanyId] = @ p__linq__0) И ([Extent1]. [ContactStatusId] <= 3) И (НЕ СУЩЕСТВУЕТ (ВЫБРАТЬ)
1 AS [C1]
FROM [dbo]. [NewsletterLog] AS [Extent2]
ГДЕ ([Extent1]. [ContactId] = [Extent2]. [ContactId]) И (6 = [Extent2]. [NewsletterLogTypeId])
))
) AS [Project2]
) AS [Project2]
ГДЕ [Project2]. [Row_number]> 99
ЗАКАЗАТЬ [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]
ОТ (ВЫБЕРИТЕ [Project2]. [ContactId] AS [ContactId], [Project2]. [CompanyId] AS [CompanyId], [Project2]. [ContactName] AS [ContactName], [Project2]. [FullName] AS [FullName] , [Project2]. [ContactStatusId] AS [ContactStatusId], [Project2]. [Создано] AS [Создано], row_number () OVER (ORDER BY [Project2]. [ContactId] ASC) AS [row_number]
ОТ (ВЫБРАТЬ
[Project1]. [ContactId] AS [ContactId],
[Project1]. [CompanyId] AS [CompanyId],
[Project1]. [ContactName] AS [ContactName],
[Project1]. [FullName] AS [FullName],
[Project1]. [ContactStatusId] AS [ContactStatusId],
[Project1]. [Создано] AS [Создано]
ОТ (ВЫБРАТЬ
[Extent1]. [ContactId] AS [ContactId],
[Extent1]. [CompanyId] AS [CompanyId],
[Extent1]. [ContactName] AS [ContactName],
[Extent1]. [FullName] AS [FullName],
[Extent1]. [ContactStatusId] AS [ContactStatusId],
[Extent1]. [Created] AS [Created],
(ВЫБРАТЬ
COUNT (1) AS [A1]
FROM [dbo]. [NewsletterLog] AS [Extent2]
WHERE ([Extent1]. [ContactId] = [Extent2]. [ContactId]) И (6 = [Extent2]. [NewsletterLogTypeId])) AS [C1]
FROM [dbo]. [Contact] AS [Extent1]
) AS [Project1]
ГДЕ ([Project1]. [CompanyId] = @ p__linq__0) И ([Project1]. [ContactStatusId] <= 3) И (0 = [Проект1]. [C1])
) AS [Project2]
) AS [Project2]
ГДЕ [Project2]. [Row_number]> 99
ЗАКАЗАТЬ [Project2]. [ContactId] ASC ', N' @ p__linq__0 int ', @ p__linq__0 = 4
Кажется, что чисто Where с EXISTS работает намного хуже, чем вычисление Count и затем выполнение Where с Count == 0.
Дайте мне знать, если вы, ребята, увидите какую-то ошибку в моих выводах. Что можно извлечь из всего этого, независимо от обсуждения Any vs Count, так это то, что любой более сложный LINQ намного лучше, если его переписать как хранимую процедуру;).