В целом производительность запроса будет в значительной степени зависеть от размера таблицы и наличия подходящих индексов.
Несколько вещей, которые я могу отметить из этого запроса:
Это утверждение не ' Это имеет большой смысл: .Where(e => e.StartDate > new DateTime())
. new DateTime()
будет инициализировать DateTime с 01/01/0001. Например, любые даты, хранящиеся в столбце SQL Server DateTime, будут относиться к 01.01.1753, так что это довольно спорный вопрос. Если значение DateTime для базы данных / объекта имеет нулевое значение, тогда .Where(e => e.StartDate.HasValue)
будет более подходящим. Если значение DateTime не имеет значения null, то это условие можно полностью исключить.
Так что, если поле имеет значение null, выражение Linq будет выглядеть примерно так:
var events = _context.Event
.Where(e => e.IsPresentation && !e.IsCanceled && e.StartDate.HasValue)
.OrderByDescending(e => e.StartDate)
.ToList();
Если он не может быть нулевым:
var events = _context.Event
.Where(e => e.IsPresentation && !e.IsCanceled)
.OrderByDescending(e => e.StartDate)
.ToList();
Следующий преступник, которого необходимо устранить: Lazy Load proxy. Есть ли у свойства Event свойства навигации для любых других объектов? Если это что-то вроде веб-приложения и вы сериализуете сущности для отправки обратно клиенту, прокси-серверы свойств EF могут абсолютно снизить производительность. Любой код после этого вызова, который касается свойства навигации, приведет к дополнительным отдельным вызовам БД, чтобы лениво загрузить эти свойства навигации. Для методов, которые возвращают списки объектов, это может быть критично. Если событие имеет ссылку на что-то вроде пользователя, и вы загружаете 1000 событий, ссылающихся примерно на 1000 пользователей, то, когда сериализатор начинает сериализацию этих 1000 событий, он будет «касаться» каждой пользовательской ссылки. Это приводит к ~ 1000 дополнительных SQL операторов, эффективно выполняющих SELECT * FROM tblUser WHERE UserId = 1
, SELECT * FROM tblUser WHERE UserId = 2
... et c. и др c. для каждого идентификатора пользователя в каждом событии. Если вам нужны эти связанные объекты, вы можете загрузить их с помощью Include(e => e.User)
, что будет быстрее, чем загрузка их по отдельности, но это означает загрузку большого количества дополнительных данных в память, которая может не понадобиться вашему клиенту / коду. Вы можете избежать отложенных загрузок, отключив отложенную загрузку и прокси, но это оставит эти сущности со ссылками #null, что означает, что любой код, ожидающий сущность Event с любыми связанными деталями, может получить одну из этих частично загруженных сущностей. (нехорошо, сущность всегда должна находиться в завершенном или готовом состоянии) Последний вариант - использовать Select
для заполнения модели представления для ваших результатов. Это может значительно ускорить запросы, потому что вы можете сделать так, чтобы EF составлял запрос для извлечения только тех данных, которые вам нужны, из каких-либо объектов, а не из-за всего или запуска ленивых загрузок.
Например, если вам просто нужны EventId, EventNumber, Name, StartDate и UserName для отображения событий:
var events = _context.Event
.Where(e => e.IsPresentation && !e.IsCanceled && e.StartDate.HasValue)
.Select(e => new EventViewModel
{
EventId = e.EventId,
EventNumber = e.EventNumber,
Name = e.Name,
StartDate = e.StartDate,
UserName = e.User.Name
})
.OrderByDescending(e => e.StartDate)
.ToList();
Это позволяет избежать ленивых попаданий при загрузке и уменьшает количество запросов. только необходимые столбцы, которые могут значительно ускорить запросы.
Далее следует посмотреть на запросы EF и их соответствующий план выполнения. Это может выделить отсутствующие / плохие индексы и любые неожиданные ленивые попадания нагрузки. Метод для этого будет зависеть от вашей базы данных, но включает в себя запуск Profiler для БД для захвата операторов SQL, выполняемых во время отладки. Отсюда вы можете захватить операторы SQL, которые генерирует EF, а затем запустить их вручную для вашей базы данных с помощью любых инструментов анализа на стороне БД. (например, SSMS с SQL сервером для получения плана выполнения, который может идентифицировать отсутствующие индексы) Хитрость отложенной загрузки Serializer в веб-приложении обнаруживается как множество дополнительных операторов SQL, выполняющихся после того, как ваш метод, кажется, завершен, но до данные возвращаются клиенту. Этот сериализатор «касается» прокси-серверов, что приводит к множеству дополнительных запросов, которые серверу приходится ждать, прежде чем данные будут возвращены клиенту.
Наконец, будет объем данных. Любая система, которая, как ожидается, будет расти со временем, должна учитывать объем данных, которые в конечном итоге могут быть возвращены. Все, что возвращает списки данных с течением времени, должно включать нумерацию на стороне сервера, где клиент отправляет размер страницы и номер страницы, где сервер может перевести это в операцию .Skip(pageNumber * pageSize).Take(pageSize)
. (/ w page # начиная с 0) Большинство сеток данных и аналогичных компонентов должны поддерживать разбиение на страницы на стороне сервера для отправки этих аргументов своим методам загрузки данных. Этим элементам управления необходимо знать общее количество строк для настройки нумерации страниц, поэтому вам потребуется метод для возврата этого количества:
var rowCount = _context.Event
.Where(e => e.IsPresentation && !e.IsCanceled && e.StartDate.HasValue)
.Count();
Те же условия, без заказа и .Count()
без ToList()
et c. создаст эффективный запрос Count.
Это должно дать вам несколько вещей, которые нужно проверить и настроить, чтобы устранить ошибки в производительности.