Функции против хранимых процедур - PullRequest
86 голосов
/ 07 октября 2008

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

Короче говоря, я хочу знать:

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

Ответы [ 11 ]

50 голосов
/ 07 октября 2008

Если вы, вероятно, захотите объединить результат этого фрагмента кода с другими таблицами, то очевидно, что табличная функция позволит вам объединить результаты в одном операторе SELECT.

Как правило, существует иерархия (View

Так что используйте тот, который минимально позволяет вам выразить желаемый результат.

49 голосов
/ 07 октября 2008

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

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

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

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

43 голосов
/ 07 октября 2008

Из документов :

Если хранимая процедура соответствует следующим критериям, она является хорошим кандидатом для перезаписи в виде табличной функции:

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

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

  • Динамические операторы EXECUTE не нужны.

  • Хранимая процедура возвращает один набор результатов.

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

12 голосов
/ 18 января 2014

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

  • Мы можем использовать функции в запросах выбора, но мы не можем использовать хранимые процедуры в избранных запросах.
  • Мы не можем использовать недетерминированные функции в функциях, но мы можем использовать недетерминированные функции в хранимых процедурах. Теперь возникает вопрос: что такое недетерминированная функция? Ответ: -

    Недетерминированная функция - это та функция, которая возвращает разные выходные данные для одинаковых входных значений в разное время, например getdate (). Он всегда возвращает другое значение при каждом запуске.

    Исключение: -

    Более ранние версии сервера SQL до SQL 2000 не позволяли использовать функцию getdate () в пользовательских функциях, но версия 2005 и более поздние позволяют нам использовать функцию getdate () в пользовательской функции.

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

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

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

8 голосов
/ 01 апреля 2013
  1. Процедура может возвращать ноль или n значений, тогда как функция может возвращать одно значение, которое является обязательным.

  2. Процедуры могут иметь входные / выходные параметры, тогда как функции могут иметь только входные параметры.

  3. Процедура позволяет выбирать в ней как оператор DML, так и функцию, тогда как функция позволяет в нем только оператор выбора.

  4. Функции могут быть вызваны из процедуры, тогда как процедуры не могут быть вызывается из функции.

  5. Исключение можно обработать блоком try-catch в процедуре, тогда как блок try-catch нельзя использовать в функции.

  6. Мы можем перейти к управлению транзакциями в процедуре, тогда как мы не можем войти в функцию.

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

  8. UDF (пользовательская функция) может использоваться в инструкциях SQL в любом месте раздела WHERE / HAVING / SELECT, тогда как хранимые процедуры не могут быть.

  9. UDF, которые возвращают таблицы, могут рассматриваться как другой набор строк. Это можно использовать в JOIN с другими таблицами.

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

6 голосов
/ 07 октября 2008

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

SELECT function_name(field1) FROM table

Это не работает для хранимых процедур.

5 голосов
/ 27 июля 2011

Я выполнил некоторые тесты с длинным битом логики, с одним и тем же битом кода (длинным оператором SELECT), выполняемым как в табличной функции, так и в хранимой процедуре, и в прямом EXEC / SELECT, и каждый из них выполнялся одинаково .

По моему мнению, всегда используйте табличную функцию, а не хранимую процедуру, чтобы возвращать набор результатов, поскольку она делает логику намного проще и удобнее для чтения в запросах, которые впоследствии присоединяются к ним, и позволяет повторно использовать ту же логику. Чтобы избежать слишком большого снижения производительности, я часто использую «необязательные» параметры (т. Е. Вы можете передать им NULL), чтобы функция могла быстрее возвращать результирующий набор, например ::100100

CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
AS
RETURN 
    SELECT DISTINCT SiteID, PersonID
    FROM dbo.SiteViewPermissions
    WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
    AND (@optSiteID IS NULL OR @optSiteID = SiteID)
    AND @RegionID = RegionID

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

SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1

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

4 голосов
/ 23 октября 2008

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

SELECT *
FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
    ON (tvf1.JoinId = tvf2.JoinId)

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

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

4 голосов
/ 07 октября 2008

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

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

Мои 2 цента

1 голос
/ 08 октября 2008

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

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