Повторное использование. Это вбито в мозг разработчиков программного обеспечения с первого дня разработки программного обеспечения. Вы хотите написать наименьшее количество кода, чтобы выполнить большую часть работы и сохранить максимальную согласованность. Вам не нужны две функции, которые должны делать одно и то же; вам нужна одна функция, на которую вы ссылаетесь всякий раз, когда вам нужно выполнить эту часть работы, чтобы вы получали одинаковые результаты для всех компонентов, составляющих вашу систему. И в целом это вполне достижимо. Если только вы не пишете T-SQL.

Повторное использование в T-SQL может быть довольно сложным.

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

Так как же добиться повторного использования в SQL Server?

Введите Определяемые пользователем типы таблиц (UDTT) и Табличные функции (или TVF). Это несколько изящных объектов, доступных в SQL Server, которые могут многое предложить, особенно при совместном использовании.

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

TVF — это просто определяемые пользователем функции, которые возвращают набор результатов вместо скалярного значения. Это означает, что вы можете написать TVF для возврата таблицы, к которой вы можете присоединиться, отфильтровать и т. д., как и любой другой набор результатов. Это имеет некоторые интересные последствия для производительности, о которых я расскажу позже. Большим преимуществом с точки зрения повторного использования является то, что TVF могут принимать табличные параметры UDTT, а также возвращать свой набор результатов как единое целое. Официальная спецификация от Microsoft находится здесь.

Соединяем их вместе

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

Одно предостережение заключается в том, что вам нужно использовать некоторые специальные команды T-SQL, чтобы все это заработало. В основном это оператор APPLY, у которого есть вариации, о которых вы можете прочитать здесь. Это аналог оператора JOIN, просто он работает именно для этих типов объектов. Как только вы используете ключевое слово несколько раз, это будет похоже на написание обычного JOIN.

И что самое приятное во всем этом? Производительность не пострадает.

Правильно, вы не должны видеть узких мест в производительности при переходе на этот шаблон. Это не похоже на скалярные функции, которые печально известны тем, что создают проблемы с производительностью (см. ссылки ниже). Использование наборов результатов вместо скалярных значений позволяет оптимизатору запросов выполнять работу заранее, как если бы весь ваш запрос был в одном месте, а не в TVF. Он обрабатывает набор результатов вашего TVF как таблицу (ага), и когда вы передаете переменную своего UDTT, это просто указатель на таблицу. Это ничем не отличается от чтения из обычной таблицы в SQL Server, за исключением того, что оно выполняется в памяти.

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

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

Скаляр, функции, встраивание и производительность

Не используйте функции скалярного значения

Использовать табличные параметры

Первоначально опубликовано на сайте blog.bandwidth.com 15 октября 2015 г.