Допустим, мне нужно реализовать фрагмент кода T-SQL, который должен возвращать в качестве результата таблицу. Я могу реализовать возвращающую табличное значение функцию или хранимую процедуру, возвращающую набор строк. Что мне использовать?
Короче говоря, я хочу знать следующее:
Каковы основные различия между функциями и хранимыми процедурами? Какие соображения я должен принять во внимание при использовании того или другого?
Ответы:
Если вы, вероятно, захотите объединить результат этого фрагмента кода с другими таблицами, то, очевидно, функция с табличным значением позволит вам объединить результаты в один оператор SELECT.
Как правило, существует иерархия (View <TV Function <Stored Proc). Вы можете делать больше в каждом из них, но возможность компоновки результатов и реального участия оптимизатора снижается по мере увеличения функциональности.
Так что используйте тот, который минимально позволяет вам выразить желаемый результат.
источник
Функции должны быть детерминированными и не могут использоваться для внесения изменений в базу данных, тогда как хранимые процедуры позволяют выполнять вставки, обновления и т. Д.
Вам следует ограничить использование функций, поскольку они создают огромную проблему масштабируемости для больших и сложных запросов. Они становятся своего рода «черным ящиком» для оптимизатора запросов, и вы увидите огромные различия в производительности между использованием функций и простой вставкой кода в запрос.
Но они определенно полезны для доходности с табличным значением в очень конкретных случаях.
Если вам нужно проанализировать список с разделителями-запятыми, чтобы имитировать передачу массива в процедуру, функция может преобразовать список в таблицу. Это обычная практика для Sql Server 2005, поскольку мы пока не можем передавать таблицы в хранимые процедуры (мы можем это сделать в 2008 году).
источник
Из документов :
источник
Я собираюсь написать несколько интересных различий между хранимыми процедурами и функциями.
Мы не можем использовать недетерминированные функции в функциях, но мы можем использовать недетерминированные функции в хранимых процедурах. Теперь возникает вопрос, что такое недетерминированная функция. Ответ: -
Исключение: -
Мы можем использовать операторы DML (вставка, обновление, удаление) в хранимой процедуре, но мы не можем использовать операторы DML в функциях для физических таблиц или постоянных таблиц. Если мы хотим выполнять операцию DML в функциях, мы можем сделать это над табличными переменными, а не над постоянными таблицами.
Мы не можем использовать обработку ошибок внутри функции, но мы можем выполнять обработку ошибок в хранимых процедурах.
источник
Процедура может возвращать ноль или n значений, тогда как функция может возвращать одно значение, которое является обязательным.
Процедуры могут иметь параметры ввода / вывода для него, тогда как функции могут иметь только параметры ввода.
Процедура позволяет выбрать, а также оператор DML в нем, тогда как функция позволяет только оператор выбора в нем.
Функции можно вызывать из процедуры, тогда как процедуры нельзя вызывать из функции.
Исключение может быть обработано блоком try-catch в процедуре, тогда как блок try-catch не может использоваться в функции.
Мы можем перейти к управлению транзакциями в процедуре, тогда как мы не можем перейти к функции.
Процедуры нельзя использовать в операторе выбора, тогда как функция может быть встроена в оператор выбора.
UDF (функция, определяемая пользователем) может использоваться в операторах SQL в любом месте раздела
WHERE
/HAVING
/,SELECT
тогда как хранимые процедуры - нет.UDF, возвращающие таблицы, можно рассматривать как другой набор строк. Это можно использовать в
JOIN
s с другими таблицами.Встроенные пользовательские функции могут рассматриваться как представления, которые принимают параметры, и могут использоваться в
JOIN
s и других операциях с наборами строк.источник
Если у вас есть функция, вы можете использовать ее как часть своего оператора SQL, например
SELECT function_name(field1) FROM table
Для хранимых процедур это не работает.
источник
Я провел несколько тестов с длительной логикой, с одним и тем же битом кода (длинным оператором 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
Я использовал эту технику в нескольких функциях, иногда с длинным списком «необязательных» параметров этого типа.
источник
Я лично использую функции с табличным значением, когда все, что я возвращаю, - это одна таблица без каких-либо изменений. В основном я отношусь к ним как к параметризованным представлениям.
Если мне нужно вернуть несколько наборов записей или если в таблицах будут обновляться значения, я использую хранимую процедуру.
Мои 2 цента
источник
Как упоминалось выше, функции более удобочитаемы / компонуются / самодокументируются, но в целом менее производительны и могут быть значительно менее производительными, если вы увлечетесь ими в таких соединениях, как
SELECT * FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1 INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2 ON (tvf1.JoinId = tvf2.JoinId)
Часто вам просто нужно согласиться с избыточностью кода, которую tvf может устранить (с неприемлемой ценой производительности).
Еще один момент, о котором я еще не упоминал, заключается в том, что вы не можете использовать временные таблицы с изменением состояния базы данных внутри многопользовательского tvf. Наиболее функционально эквивалентный механизм временной таблице - это переменная таблицы памяти без изменения состояния, а для больших наборов данных временная таблица, вероятно, будет более производительной, чем табличная переменная. (Другие альтернативы включают динамические таблицы и общие табличные выражения, но на определенном уровне сложности они перестают быть хорошим вариантом IMO.)
источник
Я бы проверил оба. Скорее всего, подход sp или производная таблица будет значительно быстрее, чем функция, и если да, то следует использовать этот подход. В общем, я избегаю функций, потому что они могут снижать производительность.
источник
Это зависит от ситуации :) Если вы хотите использовать результат с табличным значением в другой процедуре, вам лучше использовать функцию с табличным значением. Если результаты предназначены для клиента, обычно лучше использовать сохраненную процедуру.
источник
Хранимые процедуры - это предварительно скомпилированные запросы, которые выполняются быстрее и избавляют от инъекций sql. Они могут возвращать 0 или N значений. Мы можем выполнять операции DML внутри хранимых процедур. Мы можем использовать функции внутри процедур и можем использовать функции в запросе выбора. Функции используются для возврата любого значения, а операции DML невозможны в функциях. функции бывают двух типов: скалярные и табличнозначные. скалярная функция возвращает одно значение, функция с табличным значением, используемая для возврата строк таблиц.
источник