Производительность для использования предложений where 2 в LINQ
В LINQ-to-Entities вы можете запросить объекты, выполнив:
var students = SchoolContext.Students.Where(s => s.Name == "Foo" && s.Id == 1);
Я знаю, что за кулисами он будет переведен в SQL на нечто похожее на:
SELECT *
FROM Students
WHERE Name = 'Foo' AND Id = 1
Однако есть ли разница (по производительности), если я пишу:
var students = SchoolContext.Students
.Where(s => s.Name == "Foo")
.Where(s => s.Id == 1);
Будет ли он переведен на тот же SQL-запрос? Из моего понимания .Where()
вернет IEnumerable<T>
, поэтому второй .Where()
будет фильтровать сущности in-memory вместо перевода IQueryable<T>
в SQL, это правильно?
Ответы
Ответ 1
Первое предложение .Where()
все равно вернет IQueryable<T>
. Пока вы работаете с IQueryable<T>
, он продолжит сбор SQL-запроса и выполнит его, когда сбор должен быть внесен в память (например: как указано в @anaximander при использовании в цикле foreach
или ToList()
операции.
Таким образом:
SchoolContext.Students.Where(s => s.Name == "Foo").Where(s => s.Id == 1);
Все еще переводится как:
SELECT *
FROM Students
WHERE Name = 'Foo' AND Id = 1
В то время как приведенные ниже операторы 2 переведут один и тот же запрос:
SchoolContext.Students.Where(s => s.Name == "Foo").Where(s => s.Id == 1);
SchoolContext.Students.Where(s => s.Name == "Foo" && s.Id == 1);
Ответ 2
First Где возвращает IQueryable<T>
, поэтому разница в производительности не будет.
Ответ 3
Нет, это будет тот же запрос.
Вы можете составить более сложный запрос плавно, связав IQueryable
, возвращаемый каждой операцией Linq. Оператор не генерируется и не отправляется на сервер до тех пор, пока вы не оцените результаты.
Вы можете проверить фактический запрос, сгенерированный путем отладки и зависания запроса или сделать ToTraceString()
, или с помощью инструмента, такого как SQLProfiler, для мониторинга сервера базы данных.
Ответ 4
Оба должны создать один и тот же SQL; IQueryable
умный, поскольку он фактически не оценивает, пока это не понадобится. Второй .Where()
должен добавить к первому, а затем всякий раз, когда вы используете .ToList()
, .Count()
, foreach
или что-либо, что должно знать, что в IQueryable
, оно будет генерировать SQL, запросить базу данных и дать вам результат.
Ответ 5
Получить Linqpad и попробовать различные запросы. Вы можете напрямую добавить соединение к своим объектам, запустить запросы и посмотреть, какой SQL создается в каждом случае. Отличный способ экспериментировать с Linq.