Есть ли разница в производительности между этими двумя запросами LINQ to SQL?

Недавно я изучал производительность своего веб-приложения и обнаружил несколько запросов LINQ, которые, я не уверен, улучшат производительность при их изменении.

В основном текущий код выглядит так:

var result = _carsRepository.GetAll()
                 .Where(x => x.Name == input.Name)
                 .FirstOrDefault();
if (result != null)
{
    throw new Exception("test");
}

Думаю поменять его на:

    var result = _carsRepository.GetAll()
                     .Where(x => x.Name == input.Name)
                     .Any();
if (result)
{
    throw new Exception("test");
}

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

Буду благодарен за любые комментарии.

Обновлено: я мог бы запустить запрос в контексте EF db, поэтому, пожалуйста, не обращайте на это внимания. Текущий репозиторий - это общий Abp.Domian.Repository. GetAll () возвращает IQueryable

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

Cee McSharpface 27.09.2018 10:22

Вы можете получить 100000000 записей обратно из базы данных, прежде чем делать where, если нет, вам, вероятно, нужно проиндексировать Name

TheGeneral 27.09.2018 10:25

@Saruman: index or not on Name не имеет отношения к этому вопросу, потому что Where точно такой же в обеих очередях.

Tim Schmelter 27.09.2018 10:26

@TimSchmelter, вы правы, однако я просто догадываюсь, прежде чем я перейду к следующему вопросу

TheGeneral 27.09.2018 10:26

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

jeroenh 27.09.2018 10:26

Общее правило: если вам нужна только логическая обратная связь, используйте функцию Linq, которая делает именно это. Может быть, это не сильно повлияет на производительность, но это более ясно показывает ваши намерения.

Magnus 27.09.2018 10:31

Большое спасибо за ваши комментарии. Они очень полезны. Мне просто интересно, почему кто-то отклонил мой вопрос? Что я сделал не так? Я просто пытаюсь учиться у более опытных разработчиков.

Grentley 27.09.2018 10:34

Нет ничего особенного жужжание. Однако вы могли бы легко попробовать это сами.

HimBromBeere 27.09.2018 10:37

Да, я мог бы попробовать это сам, но я задал этот вопрос, потому что знал, что получу нечто большее, чем простой ответ. @jeroenh подчеркнул, что использование Any () имеет больше смысла с точки зрения того, чего я хочу достичь.

Grentley 27.09.2018 10:39

Что возвращает GetAll()? И не говорите «все записи», укажите Тип.

bommelding 27.09.2018 10:40

Я только что редактировал вопрос. Он возвращает IQueryable <TEntity>

Grentley 27.09.2018 10:45

@ Грентли, этот код в цикле? это может быть быстрее, если это так.

user9401448 27.09.2018 10:59

Вам не нужны все машины, вам не нужен список названий машин, чтобы увидеть, соответствует ли одна из них. Вам не нужно получать весь объект, если вам не нужно только одно поле. Итак, я выберу наиболее читаемый _carsRepository.GetAll().Any(x => x.Name == input.Name). Таким образом, из базы данных не будет возвращаться ни один объект, только логическое значение.

Drag and Drop 27.09.2018 10:59
stackoverflow.com/a/8340268/6527049
vivek nuna 27.09.2018 11:01

И Exception должно быть исключительным.

Drag and Drop 27.09.2018 11:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
15
256
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Мы не можем сказать вам, потому что мы не знаем, что делает ваш класс репозитория, и мы не знаем, как ваш драйвер базы данных обрабатывает преобразование в SQL.

Протестируйте и то и другое, сравните их, посмотрите SQL и проверьте с помощью инструментов анализа базы данных, если вам не хватает индекса или другой возможности оптимизации.

Только по Linq сказать невозможно.

Это действительно отвечать? Похоже на комментарий для меня. Вопрос, как вы правильно заметили, без ответа.

HimBromBeere 27.09.2018 10:32

@HimBromBeere На мой взгляд, сообщая кому-то Почему, что это невозможно, жестяная банка может быть ответом, особенно если он содержит альтернативные шаги вперед. Но не стесняйтесь, пусть решают рецензенты.

nvoigt 27.09.2018 10:35

Я должен был добавить несколько подробностей в свой вопрос. Мой вопрос очень общий, я мог бы делать LINQ в контексте EF db. Я просто хотел узнать, насколько велика разница.

Grentley 27.09.2018 10:37

Может быть небольшая разница из-за

.FirstOrDefault() - читает все столбцы

.Any() - Просто проверьте, есть ли записи

Разница будет в основном основана на размере данных и структуре SQL, индексах и всем остальном. Рекомендуем протестировать их путем тестирования

То есть вы говорите, что если бы таблица содержала сотни столбцов, разница была бы весьма значительной?

Grentley 27.09.2018 10:40

Это зависит от столбцов таблицы и данных. например Столбец VARCHAR (MAX) занимает значительное время по сравнению с VARCHAR (20). Есть много других факторов. Я просто отвечаю на разницу из-за First () и Any ()

ManishM 27.09.2018 10:43

Нет. Вы можете не получить никакой разницы в производительности. потому что

1) Любой() вернется, как только найдет совпадение.

2) Итерация FirstOrDefault () (вероятно) останавливается, когда находит элемент, удовлетворяющий условию.

LINQ к объектам:Enumerable.Any и Enumerable.FirstOrDefault должны работать одинаково, потому что их код почти идентичен:

FirstOr По умолчанию:

foreach (TSource source1 in source)
{
    if (predicate(source1))
        return source1;
}
return default (TSource);

Любой:

foreach (TSource source1 in source)
{
    if (predicate(source1))
        return true
}
return false;

Теперь. похоже, что вы получаете все записи из базы данных в памяти, а затем применяете предложение where.

старайтесь избегать загрузки данных в память за раз. тогда это даст вам разницу в производительности

Что делать, если один из столбцов представляет собой массив байтов размером 10 МБ

Magnus 27.09.2018 13:09

это может быть то же самое и в этом случае

Janmejay Kumar 27.09.2018 14:13

Вопрос не в linq2objects. Таким образом, в случае FirstOrDefault будет сгенерирован select top 1 *, а в случае массива байтов 10 МБ в качестве одного из столбцов, которые будут извлечены. Для Any() это не так.

Magnus 27.09.2018 15:51

Как указывалось ранее, неясно, что делает ваш репозиторий. Однако, если вы следуете RepositoryPattern, вам следует рассмотреть возможность добавления Any в качестве метода в свой репозиторий.

public virtual bool Any(Expression<Func<T, bool>> predicate)
{
    return _context.Set<T>().Any(predicate);
}

Это обеспечит выполнение Any в базе данных, поскольку этот метод выполняет Any on / как IQueryable.

Если вы не используете Generics в своем репозитории, замените T своим целевым классом.

Ответ принят как подходящий

Я не уверен, что делает GetAll(). Если он перемещает все элементы из вашей базы данных в вашу локальную память, я бы не стал беспокоиться: попробуйте улучшить это утверждение. Зачем забирать все предметы, если вам нужен только первый.

Если GetAll() возвращает IQueryable<...>, то есть небольшая разница:

FirstOrDefault() изменит выражение в запросе, так что оператор SQL будет Select top 1 ... from.

После изменения выражения он попросит Provider из IQqueryable выполнить Expression, полный результат оператора SQL будет перенесен в локальную память, которая в данном случае будет одним элементом.

Any() будет делать почти то же самое, за исключением того, что SQL будет: Select top 1 1 from ...

Легко видеть, что Select top 1 1 передаст максимально одно целое число, а Select top 1 передаст все выбранные столбцы.

Следовательно, если вы хотите только проверить, есть ли какие-либо элементы, Any() более эффективен, чем FirstOrDefault.

Другие вопросы по теме