Ma première pensée ici est - quel est le problème de performances? Bien sûr, vous avez une boucle (une fois par ligne pour appliquer où) dans une boucle qui exécute une requête. Mais avez-vous de mauvais plans d'exécution ? Vos ensembles de résultats sont-ils énormes ? Mais tournons-nous vers le générique. Comment une fois résoudre ce problème? SQL ne fait pas vraiment de mémorisation (comme le souligne l'illustre @Martin_Smith). Alors qu'est-ce qu'un garçon doit faire ?
Option 1 - Nouvelle conception
Créez un tout nouveau design. Dans ce cas précis @Aaron_Bertrand souligne qu'un tableau calendrier peut répondre à vos besoins. Très bien. Cela ne vous aide pas vraiment dans les situations non calendaires, mais comme c'est souvent le cas en SQL, vous devez penser un peu différemment.
Option 2 - Appeler moins l'UDF
Réduisez l'ensemble d'éléments qui appellent cette fonction. Cela me rappelle beaucoup comment réussir pagination/comptage de lignes . Générer un petit ensemble de résultats contenant les valeurs distinctes requises puis appelez votre UDF pour qu'il ne soit appelé que quelques fois. Cela peut être une option ou non, mais peut fonctionner dans de nombreux scénarios.
Option 3 - UDF dynamique
Je vais probablement me faire huer de la pièce pour cette suggestion, mais voilà. Ce qui rend cette UDF lente, c'est l'instruction select à l'intérieur de la boucle. Si votre table de vacances change vraiment rarement, vous pouvez mettre un déclencheur sur la table. Le déclencheur écrirait et mettrait à jour UDF. La nouvelle UDF pourrait forcer brutalement toutes les décisions de vacances. Serait-ce un peu comme du cannibalisme avec SQL en écrivant du SQL ? Bien sûr. Mais cela supprimerait la sous-requête et accélérerait l'UDF. Que le chahut commence.
Option 4 - Mémorisez-le !
Bien que SQL ne puisse pas mémoriser directement, nous avons SQL CLR. Convertissez l'UDF en un udf SQL CLR. Dans CLR, vous pouvez utiliser des variables statiques. Vous pouvez facilement saisir la table Holidays à intervalles réguliers et les stocker dans une table de hachage. Ensuite, réécrivez simplement votre boucle dans le CLR. Vous pouvez même aller plus loin et mémoriser la réponse complète si c'est la logique appropriée.
Mise à jour :
Option 1 - J'essayais vraiment de me concentrer sur le général ici, pas sur l'exemple de fonction que vous avez utilisé ci-dessus. Cependant, la conception actuelle de votre UDF permet plusieurs appels à la table Holiday s'il vous arrive d'en toucher quelques-uns à la suite. L'utilisation d'une sorte de tableau de style calendrier contenant une liste de « mauvais jours » et le « jour ouvrable suivant » correspondant vous permettra d'éliminer le potentiel de plusieurs appels et requêtes.
Option 3 - Tant que le domaine est inconnu à l'avance, vous pouvez très bien modifier votre table de vacances. Pour un jour férié donné, il contiendrait le prochain jour de travail correspondant. À partir de ces données, vous pouvez cracher un UDF avec une longue déclaration de cas (quand '5/5/2012' puis '5/14/2012' ou quelque chose de similaire) en bas. Cette stratégie peut ne pas fonctionner pour tous les types de problèmes, mais pourrait bien fonctionner pour certains types de problèmes.
Option 4 - Il y a des implications pour chaque technologie. CLR doit être déployé, la configuration de SQL Server modifiée et SQL CLR est limité au framework 3.5. Personnellement, j'ai trouvé ces ajustements assez faciles, mais votre situation peut être différente (disons un DBA récalcitrant, ou des restrictions sur les modifications des serveurs de production).
L'utilisation de variables statiques nécessite les assemblages be accordé PLEINE CONFIANCE . Vous devrez vous assurer que votre verrouillage est correct.
Il y a certaines preuves qu'à très haut niveaux de transaction CLR ne fonctionne pas aussi bien que SQL direct. Dans votre scénario, cependant, cette observation peut ne pas s'appliquer car il n'y a pas de corrélatif SQL direct pour ce que vous essayez de faire (mémoriser).