Функции против хранимых процедур

88

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

Короче говоря, я хочу знать следующее:

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

Аурон
источник
1
Кажется, это идеальный ответ: stackoverflow.com/a/1179778/365188
Озаир Кафрай,

Ответы:

51

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

Как правило, существует иерархия (View <TV Function <Stored Proc). Вы можете делать больше в каждом из них, но возможность компоновки результатов и реального участия оптимизатора снижается по мере увеличения функциональности.

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

Damien_The_Unbeliever
источник
50

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

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

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

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

Эрик Зи Берд
источник
1
Но вы МОЖЕТЕ отправить XML в хранимую процедуру: stackoverflow.com/questions/144550/…
cllpse
2
Неправильно, большинство функций сервера SQL недетерминированы, например getdate на сервере MS-SQL. Каноническими функциями являются только функции ODBC (= намного быстрее + ​​индексируемые) ... Но вы очень правы, следует максимально ограничить использование функций в запросах из соображений производительности.
Стефан Штайгер
45

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

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

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

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

  • Нет необходимости в динамических операторах EXECUTE.

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

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

Кристоффер Летте
источник
12

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

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

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

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

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

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

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

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

Нирадж Кумар Ядав
источник
Каким образом операции DML поддерживаются в функциях MySQL?
Joey Pinto
@JoeyPinto. Потому что myNONsql не является жалобой на SQL. Конечно, в нем есть дополнения, но не основы.
PerformanceDBA
8
  1. Процедура может возвращать ноль или n значений, тогда как функция может возвращать одно значение, которое является обязательным.

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

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

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

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

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

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

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

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

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

Натан1138
источник
6

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

SELECT function_name(field1) FROM table

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

Илья Кочетов
источник
1
Думаю, он говорил о функциях, возвращающих табличные значения.
wcm,
1
Ну я вообще говорю. Но в моем конкретном случае я сейчас между хранимой процедурой или функцией с табличным значением.
Аурон
5

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

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

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

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

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

Мои 2 цента

wcm
источник
4

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

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

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

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

6 Джордж Джетсон
источник
1

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

HLGEM
источник
1

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

Edosoft
источник
-1

Хранимые процедуры - это предварительно скомпилированные запросы, которые выполняются быстрее и избавляют от инъекций sql. Они могут возвращать 0 или N значений. Мы можем выполнять операции DML внутри хранимых процедур. Мы можем использовать функции внутри процедур и можем использовать функции в запросе выбора. Функции используются для возврата любого значения, а операции DML невозможны в функциях. функции бывают двух типов: скалярные и табличнозначные. скалярная функция возвращает одно значение, функция с табличным значением, используемая для возврата строк таблиц.

Хариш Мадаан
источник
Это очень старый вопрос с большим количеством ответов, многие из которых (включая принятый ответ) получили большое количество голосов. Прежде чем добавить еще один ответ в такую ​​ветку, вы должны спросить себя: «Чего не хватает во всех этих существующих ответах, чтобы я написал еще один?»
APC