Функции против хранимых процедур
допустим, я должен реализовать кусок кода T-SQL, который должен возвращать таблицу в качестве результата. Я могу реализовать возвращающую табличное значение функцию или хранимую процедуру, которая возвращает набор строк. Что я должен использовать?
короче говоря, то, что я хочу знать:
каковы основные различия между функциями и хранимыми процедурами? какие соображения я должен принять во внимание для использования одного или другого?
11 ответов:
Если вы, вероятно, захотите объединить результат этого фрагмента кода с другими таблицами, то, очевидно, функция с табличным значением позволит вам составить результаты в одном операторе SELECT.
Как правило, существует иерархия (View
Так что используйте любой из них минимально позволяет выразить желаемый результат.
функции должны быть детерминированными и не могут использоваться для внесения изменений в базу данных, в то время как хранимые процедуры позволяют выполнять вставки и обновления и т. д.
вы должны ограничить использование функций, так как они создают огромную проблему масштабируемости для больших, сложных запросов. Они становятся своего рода "черным ящиком" для оптимизатора запросов, и вы увидите огромные различия в производительности между использованием функций и простой вставкой кода в запрос.
но они определенно полезно для возвращений с табличным значением в очень конкретных случаях.
Если вам нужно проанализировать список с разделителями-запятыми, чтобы имитировать передачу массива в процедуру, функция может превратить список в таблицу для вас. Это обычная практика с Sql Server 2005, так как мы еще не можем передать таблицы хранимым процедурам (мы можем с 2008 года).
Если хранимая процедура соответствует следующим критериям, она является хорошим кандидатом для перезаписи в виде возвращающей табличное значение функции:
логика выражается в одном операторе SELECT, но является хранимой процедурой, а не представлением, только из-за необходимости параметров.
хранимая процедура не выполняет операции обновления, за исключением таблицы переменная.
нет необходимости в динамических операторах EXECUTE.
хранимая процедура возвращает один результирующий набор.
основной целью хранимой процедуры является создание промежуточных результатов, которые должны быть загружены во временную таблицу, которая затем запрашивается в инструкции SELECT.
Я собираюсь написать несколько интересных различий между хранимыми процедурами и функциями.
- мы можем использовать функции в запросах Select, но мы не можем использовать сохраненные процедуры в запросах select.
мы не можем использовать недетерминированные функции в функциях, но мы можем используйте недетерминированные функции в хранимых процедурах. Теперь возникает вопрос, Что такое недетерминированная функция.. Анс-это:-
недетерминированная функция заключается в том, что функция, которая возвращает разные выходы для одних и тех же входных значений в разное время, например getdate(). Он всегда возвращает другое значение при каждом запуске.
исключение:-
более ранние версии sql server до sql 2000 не позволяют использовать функцию getdate() в пользовательских функциях, но версия 2005 и далее позволяет нам использовать функцию getdate () в пользовательской функции.
Newid() является еще одним примером non детерминированная функция, но не может быть использована в пользовательских функциях, но мы можем использовать ее в хранимой процедуре.
мы можем использовать инструкции DML(insert, update, delete) внутри сохраненного процедура, но мы не можем использовать операторы DML в функциях на физическом таблицы или постоянные таблицы. Если мы хотим сделать операцию DML в функции мы можем делать это над табличными переменными, а не над постоянными таблицами.
мы не можем использовать обработку ошибок в функции, но мы может сделать ошибку обработка в хранимых процедурах.
процедура может возвращать ноль или n значений, тогда как функция может возвращать одно значение, которое является обязательным.
процедуры могут иметь параметры ввода / вывода для него, тогда как функции могут иметь только входные параметры.
процедура позволяет выбрать, а также оператор DML в нем, тогда как функция позволяет только выбрать оператор в нем.
функции могут быть вызваны из процедуры, тогда как процедуры не могут быть вызывается из функции.
исключение может быть обработано блоком try-catch в процедуре, тогда как блок try-catch не может использоваться в функции.
мы можем пойти на управление транзакциями в процедуре, тогда как мы не можем войти в функцию.
процедуры не могут быть использованы в инструкции select, тогда как функция может быть встроена в инструкцию select.
файловой системы UDF (определенные пользователем функции) может быть используется в операторах SQL в любом месте
WHERE/HAVING/SELECTраздел, тогда как хранимые процедуры не могут быть.пользовательские функции, возвращающие таблицы можно рассматривать как еще один набор строк. Это может быть использовано в
JOINS с другими таблицами.встроенные UDFs могут быть хотя как представления, которые принимают параметры и могут быть использованы в
JOINs и другие операции набора строк.
Если у вас есть функция, вы можете использовать его как часть вашего оператора 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 может устранить (при неприемлемой стоимости производительности.)
еще один момент, который я еще не видел, заключается в том, что вы не можете использовать временные таблицы изменения состояния базы данных внутри a мульти-заявление ТВФ. наиболее функционально эквивалентным механизмом для временной таблицы является изменение состояния в переменной таблицы памяти, и для больших наборов данных временная таблица, вероятно, будет более производительной, чем переменная таблицы. (Другие варианты включают динамические таблицы и общие табличные выражения, но на некотором уровне сложности, они перестают быть хороший вариант, ИМО.)
Я бы проверил производительность обоих. Вероятно, подход sp или производная таблица будут значительно быстрее, чем функция, и если да, то этот подход следует использовать. В общем, я избегаю функций, потому что они могут быть свиньями производительности.
Это зависит :) если вы хотите использовать результат с табличным значением в другой процедуре, вам лучше использовать функцию с табличным значением. Если результаты для клиента, сохраненный proc обычно является лучшим способом пойти.
Comments