подсчитать VS выбрать в LINQ - что быстрее? - PullRequest
11 голосов
/ 16 февраля 2009

Я использую IQueryable<T> интерфейсы во всем приложении и откладываю выполнение SQL на БД до таких методов, как .ToList()

Мне нужно будет иногда находить количество определенных списков без необходимости использовать данные в подсчитываемом списке. Из своего опыта работы с SQL я знаю, что SQL COUNT () для БД гораздо менее эффективен, чем эквивалентный оператор SELECT, который возвращает все строки.

Итак, мой вопрос: будет ли меньше работы с БД для возврата счетчика из метода IQueryable<T> Count(), чем отображение IQueryable<T> в список и вызов метода Count() списка? 1011 *

Я подозреваю, что это будет, учитывая, что ToList() запустит SELECT sql, а затем в отдельном запросе подсчитает количество строк. Я надеюсь, что Count() на IQueryable<T> просто выдаст sql для запроса sql COUNT (). Но я не уверен. Вы знаете?

Ответы [ 3 ]

21 голосов
/ 16 февраля 2009

Вызов ToList() вернет подлинный List<T> со всеми данными, что означает выборку всех данных. Не хорошо.

Вызов Count() действительно должен отображать SQL для подсчета на стороне базы данных. Гораздо лучше.

Однако самый простой способ проверить это - включить регистрацию в контексте ваших данных (или каков бы ни был эквивалент для вашего конкретного провайдера) и посмотреть, какие запросы фактически отправляются.

0 голосов
/ 15 мая 2011

Если вы используете SQL Server, Count () все еще очень дорог, потому что вызывает сканирование таблицы (или сканирование индекса, см. Комментарии к основному ответу). Кроме того, по умолчанию Linq не использует уровень изоляции для чтения без использования, что ухудшает ситуацию из-за блокировки.

Если вы можете жить с результатом, являющимся грязным результатом и приближением к общему количеству строк, следующий код будет значительно быстрее, чем использование Count (). По моему опыту, значение, возвращаемое этим кодом, редко отличается от истинного количества строк.

/// <summary>A very fast method for counting rows in a table.</summary>
public static long FastRowCount(DataContext context, string tableName)
{
    const string template = "SELECT rowcnt FROM sys.sysindexes WHERE id = OBJECT_ID('{0}') AND indid < 2";
    string query = string.Format(template, tableName);
    return context.ExecuteQuery<long>(query).Single();
}
0 голосов
/ 18 февраля 2009

Я не уверен, что это жесткое и быстрое правило, но метод linq, который вы добавляете в Iqueryable, будет добавлен в дерево выражений linq - если только они не являются одним из методов, которые на самом деле вызывают оценку дерева (например, ToList и Single и т. Д.). В случае LinqToSql вы узнаете, не может ли он что-то преобразовать в оператор SQL, потому что вы получите исключение времени выполнения, сообщающее, что метод не поддерживается.

например

var something = dbContext.SomeTable
  .Select(c => c.col1 == "foo")
  .Distinct()
  .ToList()
  .Count()

В приведенном выше примере Select () и Distinct () включены в SQL-запрос, передаваемый на сервер, поскольку они добавляются в Iqueryable. Count () просто действует в списке, который был возвращен SQL-запросом. Таким образом, вы не хотите делать это так: -)

В вашем случае Count () определенно будет быстрее, чем Select (), потому что результирующий оператор sql действительно будет включать счетчик, поэтому серверу нужно только вернуть одно число, а не список строк.

...