Нужно ли хранить хранимые процедуры при использовании скомпилированных запросов?

При использовании скомпилированных запросов в инфраструктуре сущностей (или linq-to-sql) в сочетании с SQL Server, действительно ли есть какое-либо преимущество в производительности при использовании хранимых процедур?

Скомпилированные запросы будут кэшироваться в качестве параметризованных запросов, поэтому производительность должна быть примерно равной хранимым процедурам. Есть ли ситуация, когда хранимые процедуры будут работать значительно лучше?

- EDIT -

В ответ на ответ Якимыча ниже я не имел в виду, что скомпилированные запросы совпадают с хранимыми процедурами. Я пытаюсь выяснить, нужны ли sprocs, если вы сделали все возможные оптимизации на стороне приложения (в этом случае скомпилированные запросы). Поэтому я предполагаю, что я ищу причины, по которым хранимая процедура будет лучше, чем комбинация оптимизаций на стороне приложения и параметризованных запросов (что эффективно компилирует запросы).

Одна из причин, почему я спрашиваю об этом, состоит в том, что многие люди, похоже, думают, что хранимые процедуры больше не нужны по разным причинам (т.е. этот пост).

Ответы

Ответ 1

"Есть ли ситуация, когда хранимые процедуры будут работать значительно лучше?"

Учитывая сопоставимую часть параметризованного SQL, сгенерированную в EF или сохраненном proc, они будут работать одинаково.

Однако у администратора базы данных всегда есть возможность дополнительно оптимизировать запрос на основе их опыта с схемой БД и его шаблонами использования. Хранимая процедура позволяет им делать это легко, в отличие от приложений, использующих его, тогда как ORM не делает.

У нас есть чрезвычайно сложная база данных SQL Server, в которой есть множество внешних систем, которые реплицируют данные через триггеры. Проблема для нас с EF заключается в том, что ответственность за SQL, которая запускается в БД, станет ответственностью разработчиков приложений при использовании любой ORM, а не администраторов баз данных.

Ответ 2

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

Согласно http://msdn.microsoft.com/en-us/library/cc853327.aspx - выполняются следующие операции, когда запрос выполняется против концептуальной модели:

  • Загрузка метаданных
  • Открытие соединения с базой данных
  • Создание представлений
  • Подготовка запроса
  • Выполнение запроса
  • Загрузка и проверка типов
  • Отслеживание
  • Материализация объектов

И объяснение относительно Preparing the query:

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

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

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

ИЗМЕНИТЬ в ответ на ваши комментарии и изменения.

Мне кажется, что у вас создается впечатление, что компиляция EF-запроса каким-то образом изменит сгенерированный код SQL, который будет запущен в отношении базы данных (вы упомянули, что скомпилированные запросы приводят к параметризованным SQL-запросам?). Это не относится к делу. Независимо от того, выполняете ли вы запрос напрямую или используете compiledQuery.Invoke, тот же код SQL будет запущен в БД. Кроме того, у вас нет полного контроля над этим, вы скорее полагаетесь на ORM, чтобы генерировать его наилучшим образом. В некоторых случаях это не является оптимальным, и именно здесь входит SP.

Итак, подведем итог:

  • Компиляция запросов - это чисто оптимизация на стороне приложения. Это экономит время для компиляции запроса который снова используется в коде.
  • Хранимые процедуры могут использоваться для настройки вашего кода SQL и максимально приблизить его к вашей цели, что дает возможность получить максимальную производительность на уровне базы данных.

Ни один из методов не может заменить другой.