Функция .NET .ToList является WAY WAY слишком медленной - PullRequest
4 голосов
/ 15 апреля 2011

У нас много проблем с командой .ToList, она используется в VB.NET с веб-проектом MVC ASP.NET.

В нашей базе данных ~ 2000 записей, мы используем команду LINQ, чтобы ВЫБРАТЬ и ЗАКАЗАТЬ 2000 записей. Результат преобразуется в список методом .ToList для нашего пейджера и построителя сетки. Проблема в том, что .ToList занимает WAY WAY TOO долго (мы говорим 40-60 секунд, чтобы выполнить), поэтому наши сайты выглядят медленными как ад.

Мы протестировали эквивалентную команду SQL в базе данных, и она быстро отвечает. Это не проблема с командами или медленным сервером базы данных. Мы пробовали IEnumrable witch, который был намного быстрее, но нам нужен он в формате .ToList в конце для наших сеток. Что за сделка с .ToList? Что-нибудь, что мы можем сделать?

Вот код:

 'list = (From c In _entities.XXXXXXXXSet.Include("XXXXXX").Include("XXXXXX") _
                Where Not (c.XXXXXX Is Nothing AndAlso c.XXXXXX = String.Empty) _
                And c.XXXXXX = codeClient _
                And c.XXXXXX > dateLimite _
                Order By c.XXXXXX Descending _
                Select c).ToList()

Мы разделили код и оставили в покое только функцию .ToList, и это действительно то, что высасывает все время. Команда LINQ выполняется в кратчайшие сроки.

Большое спасибо. Том

Ответы [ 5 ]

15 голосов
/ 15 апреля 2011

Конечно, команда LINQ «выполняется» в кратчайшие сроки, потому что она просто представляет запрос. Запрос выполняется только после итерации, что и делает метод ToList.

Я бы посоветовал вам использовать операторы Skip и Take в ваших пейджерах, чтобы сузить результат, запрашиваемый из базы данных. Делая это, вы запрашиваете только 10 или 20 элементов или все, что вам нужно, что приводит к более плавному восприятию.

8 голосов
/ 15 апреля 2011

Я думаю, что было бы лучше создать страницу в запросе, а не извлекать все данные за один раз, используя Skip и Take.

list = (From c In _entities.XXXXXXXXSet.Include("XXXXXX").Include("XXXXXX") _
            Where Not (c.XXXXXX Is Nothing AndAlso c.XXXXXX = String.Empty) _
            And c.XXXXXX = codeClient _
            And c.XXXXXX > dateLimite _
            Order By c.XXXXXX Descending _
            Select c).Skip(pageSize * pageIndex).Take(pageSize).ToList();

Что в сочетании с целенаправленным кэшированием (если это возможно) должно обеспечить более быстрый пользовательский опыт.

2 голосов
/ 15 апреля 2011

Когда вы говорите «эквивалентная команда SQL в базе данных, и она быстро реагирует» - это фактические операторы SQL, которые генерирует код LINQ, или код SQL с ручной кодировкой, который логически эквивалентен?

Потому что этот LINQ-сгенерированный код может быть не очень эффективным.

1 голос
/ 16 апреля 2011

Чтобы подтвердить производительность ToList по сравнению с выполнением запроса, добавьте оператор и сравните:

  //this call iterates a query, causing a database roundtrip.
List<Row> result = query.ToList();
  //this call generates a new List by iterating the old List.
result = result.ToList();

Просматривая ваш запрос, я подозреваю, что вам понадобится codeClient и индекс для каждого изтаблицы, указанные в звонках на .Include.Возьмите сгенерированный sql и проверьте план выполнения для подтверждения.

1 голос
/ 15 апреля 2011

Для подобных вещей часто полезно запустить код в профилировщике.Может произойти замедление любого количества вещей: сеть, память, размер объекта и т. Д.

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

...