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

19

Если у меня есть вся моя бизнес-логика в коде и я использую Entity Framework, в каких ситуациях (если таковые имеются) мне лучше переместить некоторую бизнес-логику в хранимую процедуру, вместо того, чтобы хранить все это в коде?

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

Если это имеет значение, я использую MSSQL и Entity Framework.


В следующих ситуациях я использовал хранимые процедуры:

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

Другие посты, на которые я смотрел, прежде чем задавать этот вопрос:

Эми Барретт
источник
4
Обе ваши ситуации являются вполне законным основанием для написания хранимых процедур. Вы спрашиваете, почему они законны?
Роберт Харви
@RobertHarvey Я проверял их законность и искал другие сценарии или причины, по которым вы могли бы сделать исключение и написать хранимую процедуру, а не хранить ее в коде.
Эми Барретт
Вы сделаете исключение и напишите хранимую процедуру, когда решите, что она решает проблему лучше, чем другие доступные вам методы, и это именно то, что вы сделали.
Роберт Харви

Ответы:

10

У вас уже есть пара отличных сценариев.

Есть много других причин тоже. EF действительно хорош в CRUD и в довольно прямой отчетности. Иногда, однако, EF не идеальный инструмент. Некоторые другие причины (сценарии) для рассмотрения использования хранимых процедур в сочетании с Entity Framework включают в себя:

  • У вас есть сложные единицы работы, возможно, включающие много таблиц, которые нельзя легко обернуть в транзакцию, используя функции EF.
  • Ваша база данных плохо работает с EF, потому что она не может использовать декларативную ссылочную целостность (ограничения внешнего ключа). Обычно это плохой сценарий, в котором вы можете оказаться, но иногда есть подходящие сценарии, такие как базы данных, используемые для процессов ETL.
  • Вам необходимо работать с данными, которые пересекают границы серверов со связанными серверами.
  • У вас есть очень сложные сценарии извлечения данных, где необходим «чистый металл» SQL для обеспечения адекватной производительности. Например, у вас есть сложные объединения, которые нуждаются в подсказках запросов, чтобы хорошо работать в вашей конкретной ситуации.
  • Ваше приложение не имеет полных разрешений CRUD для таблицы, но вашему приложению может быть разрешено работать в контексте безопасности, которому доверяет ваш сервер (например, идентификация приложения, а не пользователя). Это может произойти в ситуациях, когда администраторы баз данных ограничивают доступ таблиц к хранимым процессам только потому, что это дает им более детальный контроль над тем, кто что может делать.

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

Джоэл Браун
источник
Спасибо, Джоэл, вы упомянули несколько других сценариев, о которых я не думал.
Эми Барретт
Хороший ответ. Тем не менее, мне интересно, если у вас много пользователей, подключенных к базе данных и выполняющих сложные запросы или хранимые процедуры, разве вы не в конечном итоге сильно нагрузите сервер базы данных?
Рипал Барот
1
@RipalBarot Нет сомнений, что чем больше происходит рабочей нагрузки (чем больше пользователей, тем сложнее запросы), тем больше будут требования к серверу базы данных. Однако следует иметь в виду, что использование хранимых процедур, а не ORM, таких как Entity Framework, часто может уменьшить рабочую нагрузку (сравнительно), поскольку хранимые процедуры могут иметь предварительно скомпилированные планы запросов. Когда запрос поступает из ORM, СУБД часто приходится начинать с выяснения того, как обрабатывать запрос. Когда вы вызываете эквивалентную хранимую процедуру, база данных уже знает, как ее эффективно выполнить.
Джоэл Браун
2

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

Если это имеет значение, я использую MSSQL и Entity Framework.

Мои знания по EF ограничены, но, насколько я понимаю, EF ( просто ) ORM, как и любой другой; и, к счастью , способен использовать сырой SQL .

Если я возьму ваши два основных пункта:

Сложный отчет, который занимал минуты, чтобы запустить (это была страница в веб-приложении). Я обнаружил, что могу написать SQL, который намного эффективнее (занимает всего несколько секунд), чем то, что предоставлял LINQ.

LINQ / EF терпел неудачу, когда делал отчет. И, как вы заметили, это было SQLнамного быстрее, чем использование ORM. Но говорит ли это в пользу хранимых процедур или только против использования ORM для всего?

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

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

То же самое и здесь: простая строка подключения и и ОБНОВЛЕНИЕ, и ваша проблема решена. Эта проблема может быть решена даже с помощью ORM : просто используйте веб-сервис перед другой БД, и такая же сравнительная / изоляция будет достигнута.

Так что нечего здесь видеть.

Глядя на некоторые моменты, которые сделали другие:

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

Но SQLмогу это сделать. Здесь нет магии .

Ваша база данных не очень хорошо работает с EF

Опять же: используйте EF, когда это необходимо.

Вам нужно работать с данными, которые пересекают границы серверов со связанными серверами

Я не вижу, как помогают хранимые процедуры. Поэтому я не вижу преимущества хранимых процедур; но, возможно, кто-то проливает свет на это.

У вас есть очень сложные сценарии извлечения данных, где необходим «чистый металл» SQL для обеспечения адекватной производительности

Опять же: «Границы ЭФ ».

Ваше приложение не имеет полных разрешений CRUD для таблицы, но вашему приложению может быть разрешено работать в контексте безопасности, которому доверяет ваш сервер

Ладно. Я иду с возможно .

Пока что только половина пункта была сделана в пользу хранимых процедур.


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

1) Хранение запросов имеет преимущество простого вызова хранимой процедуры, которая инкапсулирует сложность. Поскольку планировщик запросов знает запрос, его «легче» оптимизировать. Но сохранений с текущим сложным планировщик запросов _minimal.

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

2) Тем не менее, он утверждался для хранения сложных запросов в БД. Есть две вещи для рассмотрения:

а) сложные запросы широко используют инфраструктуру БД, что увеличивает время отклика для каждого другого запроса. Вы не можете выполнять много дорогостоящих запросов параллельно . Это не говорит ни за, ни против хранимых процедур, но против сложных запросов.

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

ТЛ; др

Ничто не говорит прямо против хранимых процедур. Так что использование хранимых процедур - это нормально, если это вас радует.

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

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

Правильный ответ: когда захочешь . Но есть и другие варианты.

Томас Джанк
источник
0

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

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

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

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

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

Джон Рейнор
источник
100% согласны с последним пунктом
Ewan
0

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

Будут времена, когда вам нужны данные из базы данных, и вы просто не сможете получить их из кода своего приложения. Во многих крупных компаниях / предприятиях потребности бизнеса могут превосходить возможности ИТ-отдела. Компании покупают и продают, а их заявки приходят и уходят вместе с ними. Регулирующие агентства и банки не заботятся о том, что вы не можете создать свое масштабируемое и красиво закодированное приложение. Они могут осложнить жизнь бизнесу, поэтому вы должны сделать это.

Я сталкивался с ситуациями, когда сторонние приложения или инструменты написания отчетов не позволяют вам получить доступ к своему коду. Нет открытого исходного кода, нет API, нет веб-интерфейса и нет служб. Единственное, что у них есть, - это их собственный специальный инструмент для создания отчетов, который работает только с объектами базы данных: таблицами, представлениями, sprocs, пользовательскими функциями и т. Д. Вы размещаете логику везде, где только можете.

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

Некоторые Ad hoc запросы проще написать, пока вы не получите всю функциональность своего приложения. Мы ненавидим это. Мы отступаем, но шоу должно продолжаться.

JeffO
источник
0

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

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

Изменить: Когда разработчики спрашивают меня о логике доступа к бизнесу / данным, я говорю, что бизнес-логика - это то, как данные ведут себя и взаимодействуют, а логика доступа к данным - о том, как данные хранятся и извлекаются.

Например: в вашей доменной модели у вас могут быть сущности «Ученик» и «Учитель», оба производные от «Персона». (Не сказать, что это предпочтительнее, просто пример). Это может быть сохранено в реляционных данных как одна, две или три таблицы. Выбор зависит от того, сколько свойств у них общего, а также от требований к производительности чтения / записи.

В бизнес-логике не должно иметь значения, как хранятся эти объекты. (или они вообще находятся в RDB). Логика доступа к данным - все о том, как они физически хранятся.

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

Guran
источник
2
Как бы вы определили бизнес-логику и логику доступа к данным ?
Эми Барретт
@RobertHarvey Спасибо за ссылки. Уровень доступа к данным такой же, как логика доступа к данным? Я спрашиваю, поскольку на уровне доступа к данным, похоже, не так много реальной логики - только простые операции CRUD.
Эми Барретт
@AmyBarrett: Иногда вы пишете пользовательские методы на уровне доступа к данным, поэтому это не всегда CRUD.
Роберт Харви
@RobertHarvey Разве эти пользовательские методы не относятся к уровню бизнес-логики?
Эми Барретт
-4

Я думаю, что здесь есть три вопроса.

  1. Бизнес логика в SQL плохая. Даже если он работает быстрее индивидуально, он не масштабируется.

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

  3. EF плохо играет со спроксами. Вы потеряете много «хороших» функций и прироста производительности, отказавшись от динамической генерации запросов Linq.

Так что мой общий совет будет

  • Используйте SPROC для всех запросов SQL,

  • Не вставляйте в них бизнес-логику или какие-либо петли,

  • Не используйте EF.

Ewan
источник
Поскольку все SQL-запросы выполняются на сервере db, вы можете масштабировать только с дополнительными базами данных, а не с дополнительными вычислительными блоками.
Эван
1
Понимаю. Но тогда пункт № 1 - это просто компромисс между двумя проблемами производительности. Но будут времена, когда решение SQL будет явным выигрышем с точки зрения производительности, поэтому я не понимаю, как его можно считать категорически «плохим» на этом основании.
1
скажем, у вас есть веб-сервис, который делает расчет. Вы можете сделать это в коде или в SQL. скажем, sql быстрее в личном тесте одного расчета. Но когда сервис максимально загружен, его очень дешево и легко добавить вторую, третью, четвертую коробку с веб-сервисом, но сложно и дорого добавить вторую реплицированную базу данных
Ewan
1
это пример одного конкретного сценария, где SQL может быть плохим проектом из-за масштабируемости. Но даже тогда неясно: это зависит от ожидаемого количества пользователей, относительной стоимости выполнения вычислений в базе данных по сравнению с внешними и так далее. Конечно, вы правы в некоторых случаях, я просто не думаю, что это универсальное правило.
3
Это плохой совет, в целом. Существует множество вариантов доступа к данным, которые имеют преимущества по сравнению с хранимыми процедурами ручного кодирования и работают так же хорошо. Вы можете запускать sprocs прямо из EF; на самом деле, вы можете запустить любой SQL-запрос непосредственно из EF. Некоторая бизнес-логика работает лучше на сервере базы данных, поэтому вы не можете категорически утверждать, что она там запрещена. Объектно-реляционные картографы являются инструментом на 80%; они никогда не предназначались для полной замены ваших процессов доступа к данным. Используйте хранимые процедуры для того, для чего они предназначены: 20%, которые ORM не преуспевает.
Роберт Харви