Является ли использование хранимых процедур плохой практикой?
У нас есть приложение, написанное на C#, которое подключено к ms sql server. Мы используем хранимую процедуру для каждого вызова базы данных, но затем мы заметили, что использование хранимых процедур дает нам очень большой недостаток, мы не знаем, какие хранимые процедуры нам нужно обновить, если мы изменим нашу базу данных.
теперь мне было интересно, является ли использование хранимых процедур плохим или хорошим?
12 ответов
Это не проблема SP, это проблема вашего процесса разработки. Если у вас нет нужной информации - просто получите ее.
вы можете сделать простую визуальную карту, которая показывает схему таблицы и зависимые SPs. Если БД слишком велика для визуального отображения, добавьте общий текстовый файл, состоящий из SPs и имен таблиц, от которых он зависит.
в любом случае, чем больше ваша БД, тем хуже будет ваша работа при вставке деталей вашей схемы в код приложения. При использовании SP вы гарантируете, что эта функциональность не будет удвоена и что большинство изменений произойдет на стороне БД без приложения перекомпиляции и перераспределение.
Upd
Я забыл упомянуть еще одну вещь. Хорошие инструменты DB обеспечивают простой способ найти зависимые таблицы для каждого SP. Например, в контекстном меню SP в Microsoft SQL Management Studio есть пункт "Просмотр зависимостей".
хранимые процедуры выпадают из моды уже несколько лет. В наши дни предпочтительным подходом для доступа к реляционной базе данных является использование сопоставителя O/R, такого как NHibernate или Entity Framework.
хранимые процедуры требуют много больше работы для того чтобы превратиться и поддержать. Для каждой таблицы необходимо выписать отдельные хранимые процедуры для создания, извлечения, обновления и удаления строки, а также отдельные хранимые процедуры для каждой отдельной таблицы запрос, который вы хотите сделать. Кроме того, вам нужно написать классы и/или методы в коде для вызова каждой хранимой процедуры. Сравните это с O / R mapper: все, что вам нужно написать, - это определения классов, таблица базы данных и файл сопоставления. Фактически, современные ОРМ используют конвенционный подход, который устраняет необходимость в отдельном определении отображения.
хранимые процедуры способствуют плохой практике разработки, в частности, они требуют, чтобы вы нарушали DRY (не повторяйтесь), так как вам нужно ввести список полей в таблицу базы данных полдюжины раз или больше по крайней мере. Это огромная боль, Если вам нужно добавить один столбец в таблице базы данных. Невозможно передать объект в качестве параметра хранимой процедуре, только простые типы (строка, целое число, дата/время и т. д.) делают почти невозможным избежать огромных списков параметров (дюжина или более).
хранимые процедуры способствуют плохие методы управления конфигурацией. Это вытекает из аргумента о том, что DBAs должны иметь возможность изменять их независимо от самого кода. Это приводит к тому, что версия вашего кода переходит в производство, которая никогда не была протестирована на интеграцию, не соответствует ни одной конкретной ревизии в системе управления версиями и может даже не соответствовать любой ревизия в системе управления версиями вообще. В принципе, если у вас нет аудируемой записи, конец в конец, какой именно редакции ваш код находится в производстве, вы столкнетесь с проблемами.
хранимые процедуры должны развертываться отдельно от основной части кода. Если у вас нет полностью автоматизированного процесса для их обновления, существует резко возросший риск того, что они могут выйти из синхронизации с вашей основной кодовой базой в одной или нескольких средах, что приведет к ошибкам. Это особенно проблематично, если для отслеживания ревизии необходимо использовать инструмент bisect системы управления версиями это привело к ошибке.
хранимые процедуры негибки. Если вы хотите запросить свои данные несколькими различными способами (разные порядки сортировки, ленивая и нетерпеливая загрузка, подкачка и т. д.), Вам нужно будет написать множество отдельных хранимых процедур для всех различных вариантов использования, в то время как ORMs дает вам гибкий, мощный язык запросов (например, Linq to NHibernate).
хранимые процедуры требуют, чтобы вы изобрели колеса. Если вам нужно оптимистичный параллелизм, или единица шаблона работы, или ленивая загрузка, или карта идентификаторов, или обработка родительских/дочерних коллекций, или кэширование, или сопоставление иерархии классов, или почти любой другой шаблон дизайна, о котором Вы читаете в книге Мартина Фаулера,Шаблоны архитектуры корпоративных приложений, вам нужно перестроить эту функциональность самостоятельно с нуля, в то время как O / R mapper дает вам все это и многое другое прямо из коробки. Очень часто, вы будете в конечном итоге изобретение этих колес с помощью копирования и вставки кода, что снова является плохой практикой.
хранимые процедуры трудны для модульного тестирования. С помощью ORM вы можете издеваться над кодом базы данных, чтобы быстро проверить свою бизнес-логику. С помощью хранимых процедур вы должны перестроить всю тестовую базу данных с нуля.
хранимые процедуры не дают никаких преимуществ в производительности. (Крошечные) выгоды, которые вы получаете от передачи только имени sproc по проводу, в отличие от строки SQL, легко компенсируется тем фактом, что вы все, скорее всего, вызовете одну и ту же процедуру два или три раза с одинаковыми параметрами в одном запросе, в то время как ORM посмотрит на свою карту идентификации и скажет: "Эй, я уже получил это, не нужно делать еще одну поездку туда и обратно."Кроме того, утверждение о том, что хранимые процедуры кэшируются на сервере, а ad-hoc SQL-нет, является мифом, который был разорван Франсом Боума в своем блоге сообщение"хранимые процедуры-это плохо, пнятненько?"
хранимые процедуры дают мало преимуществ с точки зрения безопасности и не защищают вас от уязвимостей SQL-инъекций. Пример:
create procedure GetUsers(@SortOrder nvarchar(50))
as
begin
declare @sql nvarchar(100)
set @sql = 'SELECT * FROM Users ORDER BY ' + @SortOrder
exec @sql
end
конечно, вы можете писать хранимые процедуры, у которых нет уязвимостей SQL-инъекции, но вы также можете писать ad-hoc SQL на своем бизнес-уровне, у которого нет SQL-инъекции уязвимости с помощью параметризованных запросов. Приписывание защиты от SQL-инъекции хранимым процедурам, а не разбиение строк SQL вместе, является отвлекающим маневром и полностью вводит в заблуждение.
Я считаю, что SP хороши для вычислений / обработки данных / источников данных отчета в БД.
при использовании его исключительно для получения данных / обновления строк таблицы вы столкнетесь с целым миром боли.
Это подход, которому следуют некоторые слои доступа к данным, и получение данных sps для отдельной строки может стать болью.
Так что нет, я бы не рекомендовал это как лучший способ пойти.
есть 2 взгляда на это, некоторые говорят, что они злые, другие клянутся ими. Я смотрю на это с середины дороги.
плюсы
Ремонтопригодность, если вам нужно немного изменить запрос, фактически не влияя на другой код, вы можете сделать это без необходимости развертывания новых сборок
Безопасность, никаких атак SQL-инъекций, если вы не нарушаете рекомендации и не строите динамические запросы в proc
минусы
Без документации и стандартов, вещи могут быстро выйти из-под контроля, и сделать обслуживание базы данных кошмаром.
предложения
Используйте их для отчетов и для более сложных операций с базами данных, но старайтесь избегать простых операций CRUD.
Держать бизнес-логику из базы данных, которая должна быть в отдельном слое ИМХО.
хранимые процедуры полезны для применения ограничений на уровне базы данных. Легче проверить несколько хранимых процедур, ограничивающих доступ к базе данных, чем проверить каждый бит клиентского кода. Это делает их хорошими.
кроме этого, я скептик. Мне нравится иметь все в одном месте, на языке, который я могу тестировать.
вы не можете сказать, что это хорошо или плохо. Они имеют преимущества и недостатки и, в зависимости от проекта, их вес может отличаться.
преимущества:
- они выполняются СУБД напрямую, поэтому нет необходимости в промежуточной передаче данных на средний уровень, в случае нескольких запросов (сложная логика).
- позволяет иметь один слой изменения данных в БД.
некоторые недостатки:
- у вас есть логика, разделенная между средним слоем (C# в вашем случае) и слоем сохраняемости (DB), который может определить проблемы с точки зрения обслуживания.
Я работал над проектами, которые много использовали хранимые процедуры. В основном, бизнес-уровень был перенесен в базу данных, потому что руководитель команды был впечатлен каким-то гуру oracle, которого он встретил на своей предыдущей работе.
код хранимой процедуры сложнее поддерживать, чем C# (в Visual Studio), поскольку инструменты хуже, отладка сложнее и т. д.
в то же время, имея четкие интерфейсы для ваших правил данных. Думая о том, какие запросы будут выполняться в базе данных, можно хорошая вещь.
попробуйте сохранить код генерации и миграции (обновления) базы данных в системе управления версиями. Включите хранимые процедуры, если они вам действительно нужны. Держите логику хранимых процедур максимально простой (не делайте никакой бизнес-логики, просто стиль согласованности). Возможно, даже генерировать их из более абстрактного представления (вместе с кодом C# для их вызова).
ваш wan't знать, влияют ли изменения схемы БД на SP. Это означает, что команда, которая изменяет DB, не пишет SPs. В этом контексте переход от SP к встроенному SQL или ORM не поможет вам. Вместо проверки SP вам придется проверить свой код. Я предлагаю вам купить хорошие инструменты, которые показывают вам зависимости между вашими таблицами и SP.
вот почему вам нужна хорошая документация и хороший DBA для написания такого программного обеспечения.
хранимые процедуры IMHO неплохи, их можно использовать для многих полезных вещей, таких как триггеры или выполнение некоторых сложных запросов, где вам придется писать много запросов на стороне клиента. Но конечно нет ничего, только хорошее. Некоторые недостатки, которые я нашел: хранимые процедуры могут вызвать гораздо больше работы на стороне сервера (что иногда можно переместить на сторону клиента) и иногда их трудно поддерживать.
но, с другой стороны, они очень полезны, когда однажды вам придется предоставить доступ к базе данных некоторым программистам, пишущим программное обеспечение, например, на Java, которые не смогут использовать все те классы БД, которые вы написали на C#. В этом случае хорошо иметь некоторую логику в базе данных, чтобы вы могли использовать ее независимо от используемого клиента или языка.
хранимые процедуры действительно хороши для запросов, которые очень распространены, которые не будут часто меняться. Если у вас есть SP для "getname", который всегда вытаскивает имя и фамилию из таблицы, это будет хорошо, чтобы сохранить в долгосрочной перспективе. Кроме того, если у вас есть очень сложный запрос, который может занять много лошадиных сил на клиентском конце, хранимая процедура поможет.
любой запрос, который может быть динамическим, не должен быть SP. Если это что-то, что часто меняется, или что-то вам нужен быстрый доступ к, это плохая идея, чтобы сделать СП. Вот почему. Предположим, вы создаете хороший SP, который получает определенный тип данных. У вас есть 3 разных проекта, которые используют его. Но вам нужно что-то немного другое, поэтому ваш выбор:
- изменение хранимой процедуры и риск нарушения всех зависимых приложений
- создание новой хранимой процедуры, которая очень похожа на вашу функцию.
все хранимые процедуры для некоторые потребности, но не для других. Оцените, насколько могут измениться ваши потребности или каковы недостатки использования стандартного запроса.
еще одно большое преимущество хранимых процедур заключается в том, что вы можете вносить изменения на бэкэнде "на лету", не требуя передислокации приложения (если прототип не изменяется).
в большой компании, в которой я работаю, развертывание кода является важным упражнением, требующим не менее 30 дней и нескольких утверждений. Изменение БД может быть сделано практически сразу.
наконец, помните, что хранимые процедуры также могут обеспечить защиту от плохого программисты. У вас отличный DBA, но команда подрядчиков с самыми дешевыми предложениями пишет ваш код? DBA может записывать хранимые процедуры, а затем удалять разрешения DML из таблиц, заставляя код проходить хранимую процедуру для внесения любых изменений. Таким образом, вам не нужно беспокоиться, что какой-то парень собирается поместить SQL в код, который случайно уничтожит половину БД.
порядок хранения, как правило, хорошая вещь:
- Они более эффективны, чем стандартные запросы, особенно для определенных операций.
- Они помогают отделить вашу проектную группу базы данных от вашей проектной группы дела.
- Они дадут вам хорошую защиту от SQL-инъекций
- Они позволяют легко определить отдельные разрешения пользователя для отдельных операций