Моя первая мысль здесь - в чем проблема производительности? Конечно, у вас есть цикл (один раз для каждой строки, где он применяется) внутри цикла, в котором он выполняет запрос. Но вы получаете плохие планы выполнения? Ваш набор результатов огромен? Но давайте обратимся к общему. Как однажды решить эту проблему? SQL на самом деле не делает запоминания (как указывает выдающийся @Martin_Smith). Так что же делать мальчику?
Вариант 1 - новый дизайн
Создайте совершенно новый дизайн. В этом конкретном случае @Aaron_Bertrand указывает, что таблица календаря может удовлетворить ваши потребности. Совершенно верно. Это не очень помогает в ситуациях, не связанных с календарем, но, как это часто бывает в SQL, нужно думать немного иначе.
Вариант 2 - Вызов UDF Меньше
Сузить набор элементов, вызывающих эту функцию. Это очень напоминает мне, как сделать успешный подсчет страниц / строк . Создайте небольшой набор результатов, который имеет требуемые значения , а затем вызовите ваш UDF, чтобы он вызывался только несколько раз. Это может или не может быть вариантом, но может работать во многих сценариях.
Вариант 3 - Динамический UDF
Я, вероятно, выскользну из комнаты за это предложение, но здесь идет. Что делает этот UDF медленным, так это оператор выбора внутри цикла. Если ваш праздничный стол действительно редко меняется, вы можете поставить на него триггер. Триггер выписал бы и обновил UDF. Новый UDF мог грубой силой принять все праздничные решения. Будет ли это немного похоже на каннибализм с написанием SQL SQL? Конечно. Но это избавит от подзапроса и ускорит UDF. Пусть начинается хеклинг.
Вариант 4 - Memoize It!
Хотя SQL не может напрямую запоминать, у нас есть SQL CLR. Преобразуйте UDF в SQL CLR udf. В CLR вы можете использовать статические переменные. Вы можете легко взять таблицу Holidays через некоторый регулярный интервал и сохранить их в хеш-таблице. Затем просто перепишите ваш цикл в CLR. Вы могли бы даже пойти дальше и запомнить весь ответ, если это соответствует логике.
Обновление:
Вариант 1 - я действительно пытался сосредоточиться на общем, а не на примере функции, которую вы использовали выше. Тем не менее, текущий дизайн вашей UDF допускает несколько вызовов таблицы Holiday, если вам выпало несколько раз подряд. Использование какой-либо таблицы в стиле календаря, содержащей список «плохих дней» и соответствующий «следующий рабочий день», позволит вам исключить возможность множественных обращений и запросов.
Вариант 3 - Хотя домен заранее неизвестен, вы вполне можете изменить свой праздничный стол. Для данного выходного дня он будет содержать следующий соответствующий рабочий день. Из этих данных вы могли бы выложить UDF с длинным регистром (когда «5/5/2012», затем «5/14/2012» или что-то подобное) внизу. Эта стратегия может работать не для всех типов проблем, но может хорошо работать для некоторых типов проблем.
Вариант 4. У каждой технологии есть последствия. Необходимо развернуть CLR, изменить конфигурацию SQL Server, а SQL CLR ограничен платформой 3.5. Лично я нашел эти корректировки достаточно простыми, но ваша ситуация может быть другой (скажем, непокорный администратор базы данных или ограничения на модификации производственных серверов).
Использование статических переменных требует, чтобы сборки были предоставлены FULL TRUST . Вам нужно убедиться, что вы правильно установили блокировку.
Есть некоторые доказательства , что при очень высоких уровнях транзакций CLR не работает так же хорошо, как прямой SQL. Однако в вашем сценарии это наблюдение может быть неприменимо, поскольку нет прямого SQL-корреляции для того, что вы пытаетесь сделать (запомните).