Примітка: цю відповідь я написав, коли Entity Framework 4 був фактичним. Сенс цієї відповіді полягав у тому, щоб не потрапляти на банальне .Any()
порівняльне .Count()
тестування. Справа полягала в тому, щоб сигналізувати, що EF далеко не ідеальний. Новіші версії кращі ... але якщо у вас є частина коду, який повільний, і він використовує EF, протестуйте з прямим TSQL і порівнюйте продуктивність, а не покладайтесь на припущення ( .Any()
це ВЖЕ швидше, ніж .Count() > 0
).
Хоча я згоден з більшістю голосуючих відповідей та коментарів - особливо щодо намірів розробника точкових Any
сигналів краще, ніж - у мене була ситуація, коли Count швидше на порядок на 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
у всіх випадках.
EDIT: Тут створюються 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]. [Створено] AS [Створено]
FROM (SELECT [Project2]. [ContactId] AS [ContactId], [Project2]. [CompanyId] AS [CompanyId], [Project2]. [ContactName] AS [ContactName], [Project2]. [FullName] AS [FullName] , [Project2]. [ContactStatusId] AS [ContactStatusId], [Project2]. [Створено] AS [Створено], row_number () НАД (ЗАМОВЛЕННЯ [Project2]. [ContactId] ASC) AS [row_number]
ВІД (ВИБР.)
[Extent1]. [ContactId] AS [ContactId],
[Обсяг1]. [CompanyId] AS [CompanyId],
[Extent1]. [ContactName] AS [ContactName],
[Extent1]. [FullName] AS [FullName],
[Extent1]. [ContactStatusId] AS [ContactStatusId],
[Обсяг1]. [Створено] ЯК [Створено]
ВІД [dbo]. [Контакт] AS [Обсяг1]
WHERE ([Extent1]. [CompanyId] = @ p__linq__0) AND ([Extent1]. [ContactStatusId] <= 3) І (НЕ існує)
1 AS [C1]
ВІД [dbo]. [NewsletterLog] AS [Обсяг2]
WHERE ([Extent1]. [ContactId] = [Extent2]. [ContactId]) AND (6 = [Extent2]. [NewsletterLogTypeId])
))
) AS [Project2]
) AS [Project2]
WHERE [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]. [Створено] AS [Створено]
FROM (SELECT [Project2]. [ContactId] AS [ContactId], [Project2]. [CompanyId] AS [CompanyId], [Project2]. [ContactName] AS [ContactName], [Project2]. [FullName] AS [FullName] , [Project2]. [ContactStatusId] AS [ContactStatusId], [Project2]. [Створено] AS [Створено], row_number () НАД (ЗАМОВЛЕННЯ [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],
[Проект1]. [Створено] ЯК [Створено]
ВІД (ВИБР.)
[Extent1]. [ContactId] AS [ContactId],
[Обсяг1]. [CompanyId] AS [CompanyId],
[Extent1]. [ContactName] AS [ContactName],
[Extent1]. [FullName] AS [FullName],
[Extent1]. [ContactStatusId] AS [ContactStatusId],
[Обсяг1]. [Створено] ЯК [Створено],
(ВИБР
COUNT (1) AS [A1]
ВІД [dbo]. [NewsletterLog] AS [Обсяг2]
WHERE ([Extent1]. [ContactId] = [Extent2]. [ContactId]) AND (6 = [Extent2]. [NewsletterLogTypeId])) AS [C1]
ВІД [dbo]. [Контакт] AS [Обсяг1]
) AS [Проект1]
WHERE ([Project1]. [CompanyId] = @ p__linq__0) AND ([Project1]. [ContactStatusId] <= 3) AND (0 = [Project1]. [C1])
) AS [Project2]
) AS [Project2]
WHERE [Project2]. [Row_number]> 99
ЗАМОВИТИ [Project2]. [ContactId] ASC ', N' @ p__linq__0 int ', @ p__linq__0 = 4
Це здається чистим. Де з EXISTS працює набагато гірше, ніж обчислити підрахунок, а потім зробити, де з Count == 0.
Повідомте мене, якщо ви, хлопці, бачите якусь помилку в моїх висновках. Що можна зробити з усього цього, незалежно від будь-якого обговорення проти підрахунку, - це те, що будь-який складніший LINQ є набагато кращим, коли він буде переписаний як Зберігана процедура;).