24
SQL Server 2008-2016 Dominique Verrière Dialogue Formation Informatique SQL Server 2008-2016 Fonctions CLR et in memory

Fonctions CLR et in memory - dominique verrieredominiqueverriere.fr/Articles/DV_Fonctions_CLR_et_InMemory.pdf · Fonctions de type CLR puis in memory SQL Server: Le blog de Dominique

  • Upload
    others

  • View
    12

  • Download
    0

Embed Size (px)

Citation preview

SQL Server 2008-2016

Dominique Verrière

Dialogue Formation Informatique

SQL Server 2008-2016

Fonctions CLR et in memory

SQL Server : Le blog de Dominique Verrière 2

Introduction

Ce petit fascicule fait partie d’une liste de notes que je publie gratuitement sur mon site.

J’essaie de mettre dans ces notes mon expérience de terrain en toute indépendance de Microsoft.

Dominique Verrière

Table des matières Fonctions scalaires : le besoin ...................................................................................... 6

Fonctions de type CLR embarqué ................................................................................. 9

Fonctions triviales .................................................................................................................................................. 9

Approche classique en Transact SQL ................................................................................................................. 9

Approche en CLR embarqué ............................................................................................................................ 10

Mesure de performances ................................................................................................................................ 11

Fonctions plus complexes .................................................................................................................................... 13

Approche classique en Transact SQL ............................................................................................................... 13

Approche en C# embarqué .............................................................................................................................. 14

Mesure de performances ................................................................................................................................ 15

Conclusions ...................................................................................................................................................... 16

Fonctions in memory (2016 et +) ................................................................................ 17

Historique ............................................................................................................................................................ 17

Fonctions triviales ................................................................................................................................................ 17

Les prés requis ................................................................................................................................................. 17

Mesure de performances ................................................................................................................................ 19

Fonctions plus complexes .................................................................................................................................... 21

Conclusion ....................................................................................................................................................... 23

Contacter l’auteur ...................................................................................................... 24

Sommaire

SQL Server : Le blog de Dominique Verrière 5

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Fonctions scalaires : le besoin

Dans tout langage de programmation le besoin de fonctions scalaires est immédiat :

On devra toujours traiter des chaines de caractères, des dates, des nombres, etc…

C’est ce qui définit une fonction scalaire : elle retourne une valeur, à la différence des fonctions de type

table dont je reparlerai dans un autre post.

Dans certains cas, ces fonctions peuvent lire des données en table, mais ce n’est pas l’objet de ce post, car je

veux me focaliser sur les aspects performances des fonctions qui ne manipulent que des variables.

Certaines fonctions sont déterministes : elles retournent toujours la même valeur pour des valeurs

identiques de paramètres.

Ainsi year(UneDate) est déterministe.

A l’inverse getdate() ne l’est pas puisque la valeur de retour change à chaque appel.

On peut voir l’aspect déterministe des fonctions ainsi :

select OBJECTPROPERTY ( id , 'IsDeterministic' ) as Deterministe ,name as Nom from sys.sysobjects where xtype in ('FN','FS')

Pourquoi s’embêter avec tout cela : il est ilmportant pour l’optimiseur de savoir si une fonction est

déterministe car elle produit un résultat stable ; de plus certaines restrictions aux index sont bien

évidemment basées sur ce critère.

De plus certaines fonctions sont précises car le type de retour n’est pas sujet aux arrondis ; au contraire des

fonctions traitant des types float ne sont pas précises.

Tout cela étant vu, on va rapidement se rendre compte que Transact SQL dispose d’un panel plutôt pauvre

de fonctions scalaires pré définies.

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 7

Même si, en étant honnête, il faut reconnaitre que depuis SQL 2012 Microsoft fait des efforts pour ajouter

des fonctions à chaque version.

Il reste certain que par rapport à une formule complexe on peut :

Le premier choix a pour lui l’avantage de la performance, mais aucunement celui de la maintenabilité :

A titre d’exemple, ce genre de code est plutôt redondant :

select convert(date,DAT_EDIT) as Date1, convert(varchar,DATEPART(YY,DAT_EDIT)) + convert(varchar,LEFT(CONVERT(CHAR(20), DAT_EDIT, 101), 2)) as Date2, convert(varchar,LEFT(CONVERT(CHAR(20), DAT_EDIT, 101), 2))+ '-'+ convert(varchar,DATEPART(YY,DAT_EDIT)) as Date3, case when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_EDIT, 101), 2)) IN ('01','02','03') then '1ER TRIM ' + + convert(varchar,DATEPART(YY,DAT_EDIT)) when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_EDIT, 101), 2)) IN ('04','05','06') then '2EME TRIM ' + + convert(varchar,DATEPART(YY,DAT_EDIT)) when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_EDIT, 101), 2)) IN ('07','08','09') then '3EME TRIM ' + + convert(varchar,DATEPART(YY,DAT_EDIT)) when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_EDIT, 101), 2)) IN ('10','11','12') then '4EME TRIM ' + + convert(varchar,DATEPART(YY,DAT_EDIT)) END as Date4, convert(date,DAT_ANNUL) as Date5, convert(varchar,DATEPART(YY,DAT_ANNUL)) + convert(varchar,LEFT(CONVERT(CHAR(20), DAT_ANNUL, 101), 2)) as Date6, convert(varchar,LEFT(CONVERT(CHAR(20), DAT_ANNUL, 101), 2))+ '-'+ convert(varchar,DATEPART(YY,DAT_ANNUL)) as Date7, case when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_ANNUL, 101), 2)) IN ('01','02','03') then '1ER TRIM ' + + convert(varchar,DATEPART(YY,DAT_ANNUL)) when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_ANNUL, 101), 2)) IN ('04','05','06') then '2EME TRIM ' + + convert(varchar,DATEPART(YY,DAT_ANNUL)) when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_ANNUL, 101), 2)) IN ('07','08','09') then '3EME TRIM ' + + convert(varchar,DATEPART(YY,DAT_ANNUL)) when convert(varchar,LEFT(CONVERT(CHAR(20), DAT_ANNUL, 101), 2)) IN ('10','11','12') then '4EME TRIM ' + + convert(varchar,DATEPART(YY,DAT_ANNUL))

Nous allons donc, dans ce post :

Et mesurer le tout pour voir ce qui est acceptable ou pas…

Soit utiliser l’aspect inline du codage

Soit définir une fonction personnalisée

Créer des fonctions scalaires en Transact SQL

Créer des fonctions scalaires en C# embarqué sous forme de CLR

Créer des fonctions scalaires InMemory

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 9

Fonctions de type CLR embarqué

Fonctions triviales Pour cette partie, je vais simplement mettre en place une fonction TRIM qui enlève les blancs en débuts et

fin de chaine…

Elle est plutôt basique mais son absence oblige les développeurs Transact SQL à copier-coller le fameux :

ltrim(rtrim(@Entree))

Approche classique en Transact SQL

On peut facilement créer une fonction scalaire qui se substituera au manque du langage de cette façon :

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- Création de fonctions à l'ancienne drop function if EXISTS dbo.fsTrim go create function dbo.fsTrim ( @Entree varchar(max) ) returns varchar(max) begin declare @Retour varchar(max) set @Retour = ltrim(rtrim(@Entree)) return @Retour end go

Attention : les options SET ne sont pas optionnelles car elles sont embarquées dans la définition des

procédures et des fonctions ; c’est quelque chose qui ne me fait guère plaisir !

Toutes ces fonctions se retrouvent dans le niveau programmabilité de notre arbre de parcours des objets de

la base :

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Approche en CLR embarqué

Pour ce faire, il faut disposer de Visual Studio et créer un projet de type SQL Server

Une fois le projet défini, on peut facilement ajouter des composants de type fonctions en CLR C#

Voici le code de notre première fonction de Trim en C# :

[Microsoft.SqlServer.Server.SqlFunction(DataAccess =DataAccessKind.None,IsDeterministic = true,IsPrecise = true)] public static SqlString Trim(SqlString Entree) { // On enlève tous les blancs de début et de fin return new SqlString(Entree.ToString().Trim()); }

Vous pouvez remarquer que j’ai décoré la fonction des attributs évoqués en introduction

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 11

Une fois le code écrit, il reste à déployer l’assembly dans la base cible ; cela peut se faire directement

depuis Visual Studio mais aussi au moyen d’un script SQL qui ressemble à ceci :

Ici on ne voit que des ALTER puisque ma base cible dispose déjà de l’assembly en question, pour une

mise en production il faudra plutôt utiliser des CREATE ASSEMBLY.

De même les fonctions se créeront avec ce genre de script :

SET ANSI_NULLS OFF GO SET QUOTED_IDENTIFIER OFF GO IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Trim]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')) BEGIN execute dbo.sp_executesql @statement = N'CREATE FUNCTION [dbo].[Trim](@Entree [nvarchar](max)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [FonctionsCLR].[UserDefinedFunctions].[Trim]' END GO

Mesure de performances

Nous arrivons ici au point intéressant, les performances.

Pour les mesures je vais classiquement utiliser les instructions set statistics qui permettent de voir le temps

CPU et le temps passé : les deux notions sont importantes, car, en cas de multithreading, on peut tirer

avantage d’utiliser par exemple 8 cœurs.

-- Performances set statistics time on if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,rtrim(ltrim (' Verrière jean marc PEtèr hübeR ')) + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 811 ms, temps écoulé = 154 ms. --(608669 ligne(s) affectée(s))

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,dbo.fsTrim(' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 7718 ms, temps écoulé = 7977 ms. --(608669 ligne(s) affectée(s)) if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,dbo.Trim(' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur -- Temps UC = 2422 ms, temps écoulé = 361 ms. --(608669 ligne(s) affectée(s))

En mettant tout cela dans une feuille Excel, il est plus facile de mesurer les écarts :

Il apparait clairement que les instructions InLine sont imbattables pour ce genre de fonction triviale.

Par contre, on note que le CLR embarqué se défend honorablement malgré sa forte consommation de CPU :

le multi threading sauvant la situation.

Il est à noter que les calculs se font sur 600 000 lignes, ce qui est déjà respectable.

On pourra donc faire une balance :

Maintenabilité OU performances pures ?

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 13

Fonctions plus complexes

Cette fois je vais coder une fonction plus complexe qui interdira en pratique l’écriture InLine…

Mon besoin est de formater de manière homogène des noms et prénoms issus d’une API Web.

L’algorithme est donc d’enlever les blancs de début et enfin, de supprimer les blancs en nombre au milieu de

la chaine, et enfin de remplacer des caractères accentués par d’autres non accentués.

Approche classique en Transact SQL

drop function if EXISTS dbo.fsFormaterNomOuPrenom go create function dbo.fsFormaterNomOuPrenom ( @Entree varchar(max) ) returns varchar(max) begin declare @Retour varchar(max) if @Entree is null return null -- Eliminer tous les blancs gauche et droite set @Retour = ltrim(rtrim(@Entree)) -- Eliminer les double blancs à l'intérieur declare @Lg int while 1=1 begin set @Lg = len(@Retour) set @Retour = replace(@Retour,' ',' ') -- DEux blancs deviennent un if @Lg = len(@Retour) break -- plus rien à enlever end -- Passage en majuscules set @Retour = upper(@Retour) -- éliminer accents (sauf ç) ÉÈËÊÙÜÀÇ set @Retour = replace(@Retour,'É','E') set @Retour = replace(@Retour,'È','E') set @Retour = replace(@Retour,'Ê','E') set @Retour = replace(@Retour,'À','A') set @Retour = replace(@Retour,'Ù','U') set @Retour = replace(@Retour,'Ü','U') set @Retour = replace(@Retour,'Ç','Ç') return @Retour end go

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Approche en C# embarqué

Voici le code source en C# :

Une première fonction utilitaire :

private static string SupprimerBlancsInternes(string Entree, int NbeBlancsAConserver) {// D'après R Marchado // Supprime les blanc à l'intérieur de la chaine (il n'y en a plus à gauche et a droite) var Lg = Entree.Length; var tCaracteres = Entree.ToCharArray(); // Réallocation rapide int iSortie = 0, NbeBlancs = 0; for (int iEntree = 0; iEntree < Lg; iEntree++) { var ch = tCaracteres[iEntree]; if (ch != ' ') { tCaracteres[iSortie++] = ch; NbeBlancs = 0; } else { NbeBlancs++; if (NbeBlancs == NbeBlancsAConserver) { tCaracteres[iSortie++] = ch; } } } return new string(tCaracteres, 0, iSortie); }

Puis la fonction principale exposée au moteur SQL :

[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, IsPrecise = true)] public static SqlString FormaterNomOuPrenom(string Entree) { string Sortie; if (Entree == null) return null; // On supprime blanc à gauche et à droite Sortie = Entree.Trim(); // Supprimer les blancs à l'intérieur (on un garde UN si n sont présents) Sortie = SupprimerBlancsInternes(Sortie, 1); // On passe en majuscules Sortie = Sortie.ToUpper(); // On transforme les caractères 'spéciaux' Sortie = Sortie.Replace('É', 'E'); Sortie = Sortie.Replace('È', 'E'); Sortie = Sortie.Replace('Ê', 'E'); Sortie = Sortie.Replace('Ë', 'E'); Sortie = Sortie.Replace('À', 'A');

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 15

Sortie = Sortie.Replace('Ù', 'U'); Sortie = Sortie.Replace('Ü', 'U'); // Et on rend le résultat return Sortie; }

Le gros apport (que l’on ne voit pas forcément ici) est bien sûr la très grande richesse du Framework .Net :

cela sera particulièrement appréciable si vous travaillez sur des dates, heures ou encore mieux des durées,

domaine où le Transact SQL pèche particulièrement.

Mesure de performances

set statistics time on if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom, '-->' + dbo.fsFormaterNomOuPrenom (' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 57047 ms, temps écoulé = 62759 ms. --(608669 ligne(s) affectée(s)) if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom, '-->' + dbo.FormaterNomOuPrenom (' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur -- SQL Server \endash Temps d'exécution : --, Temps UC = 1219 ms, temps écoulé = 329 ms.

Là, on sent bien un écart très important !

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Conclusions

Tout cela est dû à la nature interprétée du langage Transact SQL : quand on utilise des fonctions

basiques la différence n’est pas sensible, par contre dès qu’il s’agit d’allouer dynamiquement des

chaines de caractères…

Doit-on pour autant tout faire en C# ?

C’est à évaluer car les appels de fonction InLine restent très performants ; à mon avis cela dépend

beaucoup de la fréquence d’utilisation de telles fonctions.

Les domaines de la BI avec beaucoup de conversions de données, beaucoup de rapports seront donc

plus concernés que les domaines de l’OLTP.

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 17

Fonctions in memory (2016 et +)

Historique

Les fonctionnalités InMemory sont apparues avec SQL Server 2014, d’abord avec l’utilisation de tables en

mémoire, de procédures stockées et depuis SQL 2016 de fonctions ‘pré compilées’.

Fonctions triviales Je vais de nouveau ‘tenter’ de réécrire notre fonction Trim.

create function dbo.InMemTrim (@Entree varchar(1000)) returns varchar(1000) with native_compilation, schemabinding as begin atomic with (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English') return ltrim(rtrim(@Entree)); end go

Cette première tentative est un échec car Microsoft considère que ces fonctions doivent passer après le

reste, c’est-à-dire l’utilisation des tables en mémoire.

Msg 41337, Niveau 16, État 1, Procédure ufnLeadingZeros_native, Ligne 1 [Ligne de départ du lot 0] Impossible de créer modules compilés en mode natif. Pour créer modules compilés en mode natif, la base de données doit avoir un MEMORY_OPTIMIZED_DATA qui est en ligne et qui comprend au moins un conteneur.

Les prés requis

Ok, créons donc le minimum pour héberger des tables en mémoire :

-- Ok il veut un stockage inmemory même si je ne veux pas m'en servir use master go alter database DemoSQS add filegroup fgInMemory CONTAINS MEMORY_OPTIMIZED_DATA go -- Comme pour les filestream on ajoute un répertoire conteneur alter database DemoSQS add file (name = fInMemory, filename = N'F:\SQL\SQL2016\Donnees\DemoSQSInMemory') to filegroup fgInMemory go

On note que le conteneur ressemble à celui des FilStream en ce sens qu’il s’agit d’un répertoire et non d’un

fichier.

Ceci s’explique par le fait que les fonctions InMemory vont créer des fichiers à la volée dans ce répertoire.

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Certains auront remarqué que mon morceau de script n’est pas très robuste…

Les plus prudents écriront donc :

if not exists (select * from sys.sysfilegroups where name = 'fgInMemory') alter database DemoSQS add filegroup fgInMemory CONTAINS MEMORY_OPTIMIZED_DATA go

Pour ce qui est du répertoire, il n’est pas visible dans les fichiers (ce n’en est pas un)

Par contre, on peut le trouver ici :

select * from sys.database_files

Donc :

if not exists (select * from sys.database_files where name = 'fInMemory') alter database DemoSQS add file (name = fInMemory, filename = N'F:\SQL\SQL2016\Donnees\DemoSQSInMemory') to filegroup fgInMemory go

Une fois ce pré requis passé, nous pouvons créer notre fonction :

-- Fonctions triviales drop function if EXISTS dbo.InMemTrim go create function dbo.InMemTrim (@Entree varchar(1000)) returns varchar(1000) with native_compilation, schemabinding as begin atomic with (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English') return ltrim(rtrim(@Entree)); end go

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 19

Mesure de performances

Pour ces fonctions triviales, je vais pouvoir comparer les 4 approches :

set statistics time on if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,ltrim(rtrim(' Verrière jean marc PEtèr hübeR ')) + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 702 ms, temps écoulé = 222 ms. --(608669 ligne(s) affectée(s)) if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,dbo.fsTrim(' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 7828 ms, temps écoulé = 8219 ms. --(608669 ligne(s) affectée(s)) if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,dbo.Trim(' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 2284 ms, temps écoulé = 499 ms. --(608669 ligne(s) affectée(s)) if object_id('tempdb..#t1') is not null drop table #t1 select Nom,Prenom,dbo.InMemTrim(' Verrière jean marc PEtèr hübeR ') + '<--' as NomComplet into #t1 from tmpCoureur --, Temps UC = 3203 ms, temps écoulé = 3216 ms. --(608669 ligne(s) affectée(s))

InLine

Avec une fonction Transact SQL

Avec une fonction C#

Avec une fonction InMemory

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

Pas tout à fait ce à quoi on peut s’attendre !

La fonction constructeur (écrite par l’éditeur) est moins performante qu’une fonction rapportée en C#, mais

reste tout de même plus rapide que son équivalente en Transact SQL.

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 21

Fonctions plus complexes

Tentons de passer notre fonction de formatage des noms dans ce mode In memory :

-- Fonctions plus complexes drop function if EXISTS dbo.InMemFormaterNomOuPrenom go create function dbo.InMemFormaterNomOuPrenom ( @Entree varchar(max) ) returns varchar(max) with native_compilation, schemabinding as begin atomic with (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English') declare @Retour varchar(max) if @Entree is null return null -- Eliminer tous les blancs gauche et droite set @Retour = ltrim(rtrim(@Entree)) -- Eliminer les doubles blancs à l'intérieur declare @Lg int while 1=1 begin set @Lg = len(@Retour) set @Retour = replace(@Retour,' ',' ') -- DEux blancs deviennent un if @Lg = len(@Retour) break -- plus rien à enlever end -- Passage en majuscules set @Retour = upper(@Retour) -- éliminer accents (sauf ç) ÉÈËÊÙÜÀÇ set @Retour = replace(@Retour,'É','E') set @Retour = replace(@Retour,'È','E') set @Retour = replace(@Retour,'Ê','E') set @Retour = replace(@Retour,'À','A') set @Retour = replace(@Retour,'Ù','U') set @Retour = replace(@Retour,'Ü','U') set @Retour = replace(@Retour,'Ç','Ç') return @Retour end go

Msg 10794, Niveau 16, État 98, Procédure InMemFormaterNomOuPrenom, Ligne 21 [Ligne de départ du lot 114] Le instruction GOTO n'est pas pris en charge par modules compilés en mode natif.

Il n’y a pas de GOTO dans cette fonction, voyons du côté du WHILE :

-- Fonctions plus complexes drop function if EXISTS dbo.InMemFormaterNomOuPrenom go create function dbo.InMemFormaterNomOuPrenom ( @Entree varchar(max) )

Fonctions de type CLR puis in memory

SQL Server Le blog de Dominique Verrière

returns varchar(max) with native_compilation, schemabinding as begin atomic with (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English') declare @Retour varchar(max) if @Entree is null return null -- Eliminer tous les blancs gauche et droite set @Retour = ltrim(rtrim(@Entree)) -- Eliminer les doubles blancs à l'intérieur --declare @Lg int --while 1=1 -- begin -- set @Lg = len(@Retour) -- set @Retour = replace(@Retour,' ',' ') -- DEux blancs deviennent un -- if @Lg = len(@Retour) -- break -- plus rien à enlever -- end -- Passage en majuscules set @Retour = upper(@Retour) -- éliminer accents (sauf ç) ÉÈËÊÙÜÀÇ set @Retour = replace(@Retour,'É','E') set @Retour = replace(@Retour,'È','E') set @Retour = replace(@Retour,'Ê','E') set @Retour = replace(@Retour,'À','A') set @Retour = replace(@Retour,'Ù','U') set @Retour = replace(@Retour,'Ü','U') set @Retour = replace(@Retour,'Ç','Ç') return @Retour end go

Effectivement la syntaxe WHILE BREAK ne lui plait pas, mais voyons la suite :

Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 27 [Ligne de départ du lot 114] Le fonction upper n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 28 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 29 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 30 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 31 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 32 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 33 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif. Msg 10794, Niveau 16, État 95, Procédure InMemFormaterNomOuPrenom, Ligne 34 [Ligne de départ du lot 114] Le fonction replace n'est pas pris en charge par modules compilés en mode natif.

Fonctions de type CLR puis in memory

SQL Server : Le blog de Dominique Verrière 23

Un petit tour à la documentation nous le confirme, voici ce qui est autorisé :

Ce qui reste est plus que léger !

Conclusion

Je ne sais pas où va Microsoft avec cette fonctionnalité, mais dans l’état actuel :

Les performances ne sont pas au rendez-vous

Les fonctionnalités sont plus que réduites

Une autre approche résout ces deux aspects

Contact

SQL Server Le blog de Dominique Verrière

Contacter l’auteur

Dominique Verrière est un consultant spécialisé sur les technologies SQL Server : moteur relationnel, SSIS, SSRS et SSAS. Il intervient dans les entreprises pour des missions d'audit, de suivi de performances, d'administration de bases de données. Les bases de données dont il s'occupe peuvent contenir plusieurs milliards de lignes et atteindre des Téra octets; son expérience du terrain est donc significative. Afin de compléter cet article, un blog www.dominiqueverriere.fr est régulièrement mis à jour avec des articles sur les nouveautés ou expériences nouvelles de l'auteur