Каковы плюсы и минусы хранения SQL в хранимых процедурах по сравнению с кодом

Каковы преимущества / недостатки сохранения SQL в исходном коде C# или в хранимых процедурах? Я обсуждал это с другом из проекта с открытым исходным кодом, над которым мы работаем (C# ASP.NET Forum). На данный момент большая часть доступа к базе данных осуществляется путем построения встроенного SQL на C# и обращения к базе данных SQL Server. Итак, я пытаюсь определить, что для этого конкретного проекта было бы лучше всего.

Пока у меня есть:

Преимущества в коде:

  • Легче поддерживать - не нужно запускать SQL-скрипт для обновления запросов.
  • Проще портировать на другую БД - без проков портировать

Преимущества хранимых процессов:

  • Представление
  • Безопасность

Ответов (25)

Решение

Я не фанат хранимых процедур

Хранимые процедуры БОЛЕЕ обслуживаемы, потому что: * Вам не нужно перекомпилировать приложение C# всякий раз, когда вы хотите изменить какой-либо SQL

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

  • Вы в конечном итоге повторно используете код SQL.

В языках программирования, включая C#, есть такая удивительная вещь, которая называется функцией. Это означает, что вы можете вызывать один и тот же блок кода из разных мест! Удивительный! Затем вы можете поместить повторно используемый код SQL внутрь одного из них или, если вы хотите получить действительно высокие технологии, вы можете использовать библиотеку, которая сделает это за вас. Я считаю, что они называются объектно-реляционными картографами и в наши дни довольно распространены.

Повторение кода - худшее, что вы можете сделать, когда пытаетесь создать поддерживаемое приложение!

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

У вас есть 4 веб-сервера и куча приложений Windows, которые используют один и тот же код SQL. Теперь вы поняли, что есть небольшая проблема с кодом SQl, поэтому вы лучше ...... измените процедуру в одном месте или отправьте код всем веб-серверы, переустановите все настольные приложения (может помочь щелчок один раз) во всех окнах

Почему ваши приложения для Windows подключаются напрямую к центральной базе данных? Это похоже на ОГРОМНУЮ дыру в безопасности и узкое место, поскольку оно исключает кеширование на стороне сервера. Разве они не должны подключаться через веб-службу или аналогично вашим веб-серверам?

So, push 1 new sproc, or 4 new webservers?

In this case it is easier to push one new sproc, but in my experience, 95% of 'pushed changes' affect the code and not the database. If you're pushing 20 things to the webservers that month, and 1 to the database, you hardly lose much if you instead push 21 things to the webservers, and zero to the database.

More easily code reviewed.

Can you explain how? I don't get this. Particularly seeing as the sprocs probably aren't in source control, and therefore can't be accessed via web-based SCM browsers and so on.

More cons:

Storedprocs live in the database, which appears to the outside world as a black box. Simple things like wanting to put them in source control becomes a nightmare.

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

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

Большой поклонник Transact SQL, настройка больших запросов оказалась для меня очень полезной. Я не писал ни одного встроенного SQL около 6 лет!

ПРОТИВ

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

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

ЗА

  1. Производительность того, чего она может стоить (позволяет избежать синтаксического анализа запросов драйвером БД / планом воссоздания и т. Д.)
  2. Обработка данных не встроена в код C/C++ / C#, что означает, что мне нужно просматривать меньше кода низкого уровня. SQL менее подробен и легче просматривается, если он указан отдельно.
  3. Благодаря разделению люди могут намного проще находить и повторно использовать код SQL.
  4. При изменении схемы проще что-то изменить - вам просто нужно дать тот же вывод коду, и он будет работать нормально.
  5. Легче перенести в другую базу данных.
  6. Я могу перечислить отдельные разрешения для моих хранимых процедур и управлять доступом на этом уровне.
  7. Я могу профилировать свой код запроса / сохранения данных отдельно от кода преобразования данных.
  8. Я могу реализовать изменяемые условия в своей хранимой процедуре, и ее будет легко настроить на сайте клиента.
  9. Становится проще использовать некоторые автоматизированные инструменты для преобразования моей схемы и операторов вместе, чем когда они встроены в мой код, где мне придется их выслеживать.
  10. Обеспечение передовых методов доступа к данным проще, когда у вас есть весь код доступа к данным в одном файле - я могу проверить запросы, которые обращаются к неэффективной таблице или те, которые используют более высокий уровень сериализации, или выбрать * в коде и т. Д. .
  11. Когда все это перечислено в одном файле, становится легче найти изменения схемы / изменения логики манипулирования данными.
  12. Становится проще выполнять поиск и замену правок в SQL, когда они находятся в одном месте, например, изменение / добавление операторов изоляции транзакций для всех сохраненных процессов.
  13. Я и администратор базы данных находим, что иметь отдельный файл SQL проще / удобнее, когда администратор базы данных должен проверить мои данные SQL.
  14. Наконец, вам не нужно беспокоиться об атаках SQL-инъекций, потому что какой-то ленивый член вашей команды не использовал параметризованные запросы при использовании встроенных sqls.

Самым большим преимуществом sproc в том месте, где я работаю, является то, что у нас будет намного меньше кода для переноса на VB.NET (из VB6), когда придет время. И это НАМНОГО меньше кода, потому что мы используем sprocs для всех наших запросов.

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

Вероятно, ваш язык программирования и структура приложения:

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

Если этих двух условий два, пропустите хранимые процедуры.

Вы перечисляете 2 про-очка для спрока:

Производительность - не совсем. В Sql 2000 или выше оптимизация плана запроса довольно хороша и кэшируется. Я уверен, что Oracle и т. Д. Делают аналогичные вещи. Я не думаю, что sprocs больше подходят для повышения производительности.

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

В любом случае это лучшая практика для производительности.

Linq определенно является тем способом, которым я бы сейчас занялся новым проектом. Смотрите этот похожий пост .

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

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

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

[Edit] Вот еще одно текущее обсуждение

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

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

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

Преимущества в коде:

  • Легче поддерживать - не нужно запускать SQL-скрипт для обновления запросов.
  • Проще портировать на другую БД - без проков портировать

На самом деле, я думаю, у вас все наоборот. IMHO, SQL в коде сложно поддерживать, потому что:

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

Думайте о хранимых процессах как о методах, которые вы вызываете из объекта базы данных - их намного проще повторно использовать, есть только одно место для редактирования, и в случае, если вы меняете поставщиков БД, изменения происходят в ваших хранимых процессах, а не в вашем коде. .

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

Хранимые процедуры.

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

Я не думаю, что поддерживать хранимые процедуры сложнее, вы не должны кодировать их непосредственно в базе данных, а сначала в отдельных файлах, затем вы можете просто запустить их в любой БД, которую вам нужно настроить.

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

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

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

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

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

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

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

Подумайте об этом так

У вас есть 4 веб-сервера и куча приложений Windows, которые используют один и тот же код SQL. Теперь вы поняли, что есть небольшая проблема с кодом SQl, поэтому вы лучше ...... измените процедуру в одном месте или отправьте код всем веб-серверы, переустановите все настольные приложения (может помочь щелчок один раз) во всех окнах

Я предпочитаю хранимые процессы

Также проще провести тестирование производительности с помощью процесса, поместив его в анализатор запросов, установите статистику io / time при установке showplan_text on и вуаля.

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

только мои 2 цента

Преимущества хранимых процедур :

Более простой анализ кода.

Менее связаны, поэтому их легче тестировать.

Настраивается более легко.

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

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

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

Недостатки:

Разработчикам сложнее управлять: контроль версий скриптов: у каждого есть своя база данных, интегрирована ли система контроля версий с базой данных и IDE?

@Keith

Безопасность? Почему бы sprocs быть более безопасными?

Как предлагает Komradekatz, вы можете запретить доступ к таблицам (для комбинации имени пользователя и пароля, которая подключается к базе данных) и разрешить доступ только к SP. Таким образом, если кто-то получит имя пользователя и пароль к вашей базе данных, он сможет выполнять SP, но не сможет получить доступ к таблицам или любой другой части БД.

(Конечно, выполнение sprocs может предоставить им все необходимые данные, но это будет зависеть от доступных sprocs. Предоставление им доступа к таблицам дает им доступ ко всему.)

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

Можно было бы возразить, что это просто переносит некоторую обработку с SQL на веб-сервер, но в целом это было бы хорошо.

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

Когда дело доходит до безопасности, хранимые процедуры намного безопаснее. Некоторые утверждали, что в любом случае доступ будет осуществляться через приложение. Многие люди забывают, что большинство нарушений безопасности происходят изнутри компании. Подумайте, сколько разработчиков знают «скрытые» имя пользователя и пароль для вашего приложения?

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

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

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

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

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

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

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

На мой взгляд, по этому вопросу нельзя голосовать «да» или «нет». Это полностью зависит от дизайна вашего приложения.

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

(Pseudocode)

Function createOrder(Order yourOrder) 
Begin
  Call SP_createOrder(yourOrder)
End

Итак, в конце концов у вас есть средний уровень, работающий на этом очень крутом кластере из 4 серверов, каждый из которых оснащен 16 процессорами, и на самом деле он вообще ничего не будет делать! Какая трата!

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

Плюсы хранимых процедур 1). Повышенная безопасность, поскольку SQL в хранимой процедуре статичен по своей природе (в основном). Это защитит от SQL-инъекции. 2). Возможность повторного использования. Если необходимо вернуть одни и те же данные для нескольких приложений / компонентов, это может быть лучшим выбором вместо повторения операторов SQL. 3). Уменьшает количество вызовов между клиентом и сервером базы данных.

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

Твердо придерживайтесь принципа «Хранимые процессы плохо подходят для использования CRUD / бизнес-логики». Я понимаю необходимость отчетности, импорта данных и т. Д.

Напишите здесь ...

Программистам нужен код в своем приложении. Администраторы баз данных хотят, чтобы это было в базе данных.

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

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

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

База данных является тем, чем она является, люди неизбежно вносят изменения в производственные базы данных, просто чтобы на время выбраться из тени. Затем забудьте синхронизировать его между средами и системой управления версиями. Рано или поздно рабочая база данных становится фактической записью, а не системой управления версиями - вы попадаете в ситуацию, когда вы не можете удалить какие-либо sprocs, потому что вы не знаете, используется ли она.

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

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

С другой стороны, хранимые процедуры удобны в ситуациях, когда вы вносите изменения, но не требует повторного развертывания кода приложения. Это также позволяет вам формировать ваши данные перед их отправкой по сети, где sql в коде, возможно, придется делать несколько вызовов для извлечения, чем формировать их (хотя теперь есть способы запускать несколько операторов sql и возвращать несколько наборов результатов за один вызов ", как в MARS в ADO.NET), что, вероятно, приведет к тому, что через вашу сеть будет передаваться больше данных.

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