выполнение запросов LINQ по отношению к эквиваленту SQL - PullRequest
10 голосов
/ 06 июля 2011

В настоящее время я обсуждаю с кем-то на работе производительность запросов LINQ относительно эквивалента SQL.

Кто-нибудь делал / видел какие-либо научные исследования по этому поводу?

Если нет, то в качестве примера я приведу неподтвержденную информацию о том, где вам пришлось заменить LINQ запросом SQL для повышения производительности.

Ответы [ 8 ]

9 голосов
/ 06 июля 2011

У меня есть немного другой взгляд на это; при профилировании (с нашим блестящим профилировщиком ) мы заметили, что LINQ (в данном случае с SQL) выполняет разумную работу, генерируя TSQL для базовых запросов, и операция выполняется очень быстро на сервере БД (0,5 мс и т. д.) - однако фактическая операция запроса занимала НАМНОГО дольше (например, 20 мс + для одного и того же запроса 0,5 мс, в некоторых случаях). Так где же было время? Вы можете подумать «запросить перевод», но нет; у нас также есть много ExecuteQuery<T> кода (то есть, где вы пишете TSQL вручную), и это делало точно так же . Оказалось, что где-то между материализатором и картой идентификации теряется огромное количество времени.

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

На большей части LINQ он обычно работает нормально при генерации TSQL для простых запросов, но для всего сложного я обычно доверяю TSQL, написанному вручную, гораздо больше. Чтобы взять случай в качестве примера, у меня был сложный запрос, включающий группы, пропуски и взятия. Это не очень хорошо. Когда я написал это вручную с помощью ROW_NUMBER () и т. Д., Те же результаты заняли 4% от «статистики IO» и общего времени.

Мое текущее мнение о LINQ состоит в том, что инструменты ORM делают данные мутации бризом, но для запроса я склонен использовать dapper . Что иронично, поскольку Q в LINQ - это «запрос».

6 голосов
/ 06 июля 2011

LINQ, как и в LINQ2SQL или EF, должен иметь обобщенный набор правил о том, как преобразовывать запросы LINQ в SQL, и с этим вводится уровень абстракции. Эта абстракция иногда приводит к заявлениям, которые являются неоптимальными. Написание ваших операторов SQL вручную позволяет настроить его для вашего конкретного случая.
Это приводит к выводу, что скорость SQL с большей вероятностью будет выше, особенно в сложных сценариях. Но это не значит, что каждый запрос LINQ медленнее, чем его SQL-эквивалент.
Мой опыт работы с EF 1 в сочетании с Oracle подтверждает это.

4 голосов
/ 06 июля 2011

Один из наиболее очевидных примеров, когда SQL-запрос лучше, - это пакетное обновление / удаление. В LINQ-To-SQL нет встроенного средства для обработки нескольких обновлений или удалений, за исключением обработки записей по одной, которая генерирует отдельные запросы для каждой записи.

var myRecords = myContext.Books.Where(b => b.Author = "Bob");
foreach (var rec in myRecords)
    myContext.Books.DeleteOnSubmit(rec);
myContext.SubmitChanges()  // generates delete statement for each record.

В общем случае LINQ оптимизирован для генерации очень эффективных запросов и иногда может генерировать даже лучшие запросы, чем интуитивно понятный способ написания его с помощью SQL. Однако всегда будут исключения, когда операторы LINQ-to-SQL не будут такими эффективными, как SQL-запрос, который можно написать вручную.

2 голосов
/ 06 июля 2011

LinqToSql - это слой поверх ADO.Net. Поэтому, если вы используете ADO.Net с Sql-запросами, вы будете «быстрее», чем LinqToSql (не выполняя тех дополнительных действий, которые выполняет LinqToSql).

Этот же аргумент (когда производительность является единственным критерием) может быть сделан против .Net и для машинного кода. .Net IL в конечном счете JIT'ован для Machine, и если вы просто напишете Machine в первую очередь, вы будете быстрее.

Вот пара сценариев, где это важно:

  • Если ваши запросы с низким IO и большими объемами данных, возвращаемых для материализации, LinqToSql займет намного больше времени, чем необработанный sql. С другой стороны, вы получаете экземпляры Customer вместо DataRows.
  • Если ваши запросы очень динамичны, так что вы никогда не выдаете один и тот же текст sql дважды, вы всегда будете нести расходы на перевод запроса. Sql-запросы будут выполняться быстрее (особенно если вы не учитываете построение SQL-текста).

Вот пара сценариев, где это просто не имеет значения:

  • Если ваши запросы имеют большой объем операций ввода-вывода базы данных (стиль отчета), вы не заметите дополнительных затрат ЦП на стороне клиента, связанных с абстракцией LinqToSql.
  • Если ваши запросы повторяются (один и тот же запрос с разными параметрами), большая часть стоимости абстракции LinqToSql может быть уменьшена с помощью CompiledQuery. <- Я думаю, что большинство систем соответствуют этому сценарию. </li>
0 голосов
/ 07 июля 2011

Ранее в этом году я представил отчет об ошибке производительности Linq2Sql при вставке множества записей в один набор транзакций.Каждая отдельная вставка обрабатывалась все дольше и дольше, потому что Linq2Sql должен был проверить отношения - которые сервер БД собирался проверить в любом случае.

Вы можете увидеть отчет об ошибке в https://connect.microsoft.com/VisualStudio/feedback/details/637841/linq-to-sql-shows-progressively-worse-performance-as-the-transaction-set-grows

Нажмите на подробности показа, и я включил некоторые показатели производительности.

Интересно, что ответ Microsoft состоял в том, что они не планировали улучшать производительность Linq2Sql, и что я должен использовать ADO.Net, что я уже решилdo.

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

Что касается сложных запросов - я на 50% использую Linq2Sql и около 50% хранимых процедур.Я никогда не использую встроенный SQL, потому что я предпочитаю использовать методы, которые строго типизированы.Так что для простых запросов простота Linq2Sql превосходит ADO.Net в 100% случаев.

0 голосов
/ 07 июля 2011

Вообще, по моему опыту, проблема с EF4.1 или LINQtoSQL - это не LINQ, а кодер.

Разработчики, как правило, не знают, как кодировать эффективные запросы или как кодировать эффективный и масштабируемый доступ к базе данных (т.е. они хорошо знают VB или C #, но не SQL), и это показывает, как они конструируют запрос. На этом этапе не имеет значения, используют ли они LINQ или нет.

На самом деле это проявляется, когда приложения отлично работают в процессе разработки (база данных dev имеет несколько 100 000 строк данных), но плохо работают в производственной среде (миллионы строк данных). Разработчики сразу отмечают, что в разработке все работало нормально, поэтому с базой данных должно быть что-то не так, а не с их кодом. Так начинаются войны между разработчиками и администраторами баз данных.

Хотя мне действительно нравится LINQ, вам часто лучше переносить запросы в хранимые процессы, чтобы можно было настраивать и настраивать доступ к данным без необходимости выполнять полный цикл Dev-Test-QA-Release для вашего приложения для каждого второстепенного обновить.

0 голосов
/ 06 июля 2011

Пожалуйста, проверьте другой вопрос: LINQ-to-SQL против хранимых процедур?

На мой взгляд, linq достаточно хорош для использования почти во всех аспектах.В некоторых редких случаях, когда вы очень хорошо разбираетесь в sql и действительно хотите улучшить производительность, вместо этого выбирайте raw sql.

0 голосов
/ 06 июля 2011

Когда вы запускаете запрос LINQ, LINQ генерирует код T-SQL для выполнения вашего запроса. Вы можете запустить SQL Server Profiler, чтобы получить представление о том, как выглядит запрос. Я делал это в прошлом, и сгенерированный T-SQL выглядит довольно чисто.

Я не могу говорить непосредственно о производительности, так как я не запускаю никаких чисел, но я видел одну вещь: если вы не используете столбец rowversion в своей таблице для запросов LINQ, вы получите в итоге каждый столбец в таблице, включенной в предложение WHERE, которое делается таким образом как часть встроенной оптимистической проверки параллелизма LINQ. Использование столбца rowversion позволяет LINQ использовать только этот столбец для этой проверки и обеспечивает более чистый и производительный T-SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...