Partager via


Performances de l'intégration du CLR

Cette rubrique décrit certains des choix de conception qui améliorent les performances de l’intégration de Microsoft SQL Server au Common Language Runtime (CLR) de Microsoft .NET Framework.

Processus de compilation

Lors de la compilation d’expressions SQL, lorsqu’une référence à une routine managée est rencontrée, un stub MSIL (Microsoft Intermediate Language) est généré. Ce stub inclut du code pour marshaler les paramètres de routine de SQL Server vers le CLR, appeler la fonction et retourner le résultat. Ce code de type glue est basé sur le type de paramètre et sur la direction du paramètre (in, out ou reference).

Le code de collage permet des optimisations spécifiques au type et garantit l’application efficace de la sémantique des SQL Server, telles que la nullabilité, les facettes contraignantes, la valeur par valeur et la gestion des exceptions standard. En générant le code pour les types exacts des arguments, vous évitez le conflit de types ou les coûts de création d'objet de wrapper (ou « conversion boxing ») à travers la limite d'appel.

Le stub généré est ensuite compilé en code natif et optimisé pour l’architecture matérielle particulière sur laquelle SQL Server s’exécute, à l’aide des services de compilation JIT (juste-à-temps) du CLR. Les services JIT sont appelés au niveau de la méthode et permettent à l’environnement d’hébergement SQL Server de créer une unité de compilation unique qui couvre à la fois l’exécution SQL Server et CLR. Une fois le stub compilé, le pointeur fonction résultant devient l'implémentation à l'exécution de la fonction. Cette solution de génération du code garantit qu'il n'existe pas de coûts d'appel supplémentaires en rapport avec la réflexion ou l'accès aux métadonnées au moment de l'exécution.

Transitions rapides entre SQL Server et CLR

Le processus de compilation génère une fonction pointeur qui peut être appelée au moment de l'exécution à partir du code natif. Dans le cas de fonctions scalaires définies par l'utilisateur, cet appel de fonction se produit ligne par ligne. Pour réduire le coût de la transition entre SQL Server et le CLR, les instructions qui contiennent un appel managé ont une étape de démarrage permettant d’identifier le domaine d’application cible. Cette étape d'identification réduit le coût de la transition pour chaque ligne.

Considérations relatives aux performances

L’article suivant récapitule les considérations relatives aux performances spécifiques à l’intégration du CLR dans SQL Server. Pour plus d’informations, consultez « Utilisation de l’intégration clr dans SQL Server 2005 » sur le site Web MSDN. Vous trouverez des informations générales sur les performances du code managé dans « Amélioration des performances et de la scalabilité des applications .NET » sur le site Web MSDN.

Fonctions définies par l'utilisateur

Les fonctions CLR bénéficient d’un chemin d’appel plus rapide que celui des fonctions transact-SQL définies par l’utilisateur. En outre, le code managé présente un avantage décisif en termes de performances par rapport à Transact-SQL en termes de code procédural, de calcul et de manipulation de chaîne. Les fonctions CLR gourmandes en calculs et n'effectuant pas d'accès aux données sont mieux écrites en code managé. Toutefois, les fonctions Transact-SQL permettent d’accéder aux données plus efficacement que l’intégration CLR.

Agrégats définis par l'utilisateur

Le code managé se révèle considérablement plus performant que l'agrégation à base de curseur. Le code managé fonctionne généralement un peu plus lentement que les fonctions d’agrégation intégrées SQL Server. S'il existe une fonction d'agrégation intégrée native, il est recommandé de l'utiliser. Dans les cas où l'agrégation nécessaire n'est pas prise en charge en mode natif, choisissez, si possible, un agrégat CLR défini par l'utilisateur de préférence à une implémentation à base de curseur pour des raisons de performance.

Fonctions table en continu

Les applications doivent souvent retourner une table comme résultat de l'appel d'une fonction. Les exemples incluent la lecture de données tabulaires à partir d'un fichier dans le cadre d'une opération d'importation et la conversion de valeurs séparées par des virgules dans le cas d'une représentation relationnelle. En général, vous pouvez accomplir ces actions en matérialisant la table de résultats et en la remplissant avant qu'elle ne puisse être consommée par l'appelant. L’intégration du CLR à SQL Server introduit un nouveau mécanisme d’extensibilité appelé fonction table de streaming (STVF). Les fonctions table en continu offrent de meilleures performances que les implémentations de procédure stockée étendue comparables.

Les fonctions table en continu sont des fonctions managées qui retournent une interface IEnumerable. IEnumerable possède des méthodes pour se déplacer à travers le jeu de résultats retourné par la fonction table en continu. Lorsque la fonction table en continu est appelée, l'interface IEnumerable retournée est directement connectée au plan de requête. Le plan de requête appelle les méthodes IEnumerable lorsqu'il doit extraire des lignes. Ce modèle d'itération permet que les résultats soient consommés immédiatement après que la première ligne a été créée, au lieu d'attendre que la totalité de la table soit remplie. Il réduit aussi considérablement la mémoire consommée en appelant la fonction.

Différences entre les tableaux et les curseurs

Lorsque les curseurs Transact-SQL doivent parcourir des données qui sont plus facilement exprimées en tant que tableau, le code managé peut être utilisé avec des gains de performances significatifs.

Données de type chaîne

SQL Server données de caractères, telles que varchar, peuvent être de type SqlString ou SqlChars dans les fonctions managées. Les variables SqlString créent une instance de la valeur entière en mémoire. Les variables SqlChars fournissent une interface multidiffusion qui peut être utilisée pour obtenir de meilleures performances et une meilleure évolutivité en ne créant pas d'instance de la totalité de la valeur en mémoire. Ce point est particulièrement important pour les données LOB. En outre, il est possible d'accéder aux données XML du serveur via une interface de diffusion retournée par SqlXml.CreateReader().

Différences entre le CLR et les procédures stockées étendues

Les API Microsoft.SqlServer.Server (API) qui permettent aux procédures managées de renvoyer des jeux de résultats au client s'exécutent mieux que les API ODS (Open Data Services) utilisées par les procédures stockées étendues. En outre, les API System.Data.SqlServer prennent en charge les types de données tels que xml, , varchar(max)nvarchar(max)et varbinary(max), introduits dans SQL Server 2005 (9.x), tandis que les API ODS n’ont pas été étendues pour prendre en charge les nouveaux types de données.

Avec le code managé, SQL Server gère l’utilisation des ressources telles que la mémoire, les threads et la synchronisation. Cela est dû au fait que les API managées qui exposent ces ressources sont implémentées par-dessus le SQL Server resource manager. À l’inverse, SQL Server n’a aucune vue ni aucun contrôle sur l’utilisation des ressources de la procédure stockée étendue. Par exemple, si une procédure stockée étendue consomme trop de ressources de processeur ou de mémoire, il n’existe aucun moyen de détecter ou de contrôler cela avec SQL Server. Avec le code managé, toutefois, SQL Server pouvez détecter qu’un thread donné n’a pas produit pendant une longue période, puis forcer la tâche à céder afin que d’autres travaux puissent être planifiés. Par conséquent, l'utilisation du code managé offre une meilleure évolutivité et une meilleure utilisation des ressources système.

Le code managé peut impliquer une charge mémoire supplémentaire nécessaire pour maintenir l'environnement d'exécution et effectuer les contrôles de sécurité. C’est le cas, par exemple, lors de l’exécution à l’intérieur de SQL Server et de nombreuses transitions entre le code managé et le code natif sont nécessaires (car SQL Server doit effectuer une maintenance supplémentaire sur des paramètres spécifiques au thread lors du passage au code natif et au retour). Par conséquent, les procédures stockées étendues peuvent nettement surpasser le code managé exécuté à l’intérieur de SQL Server dans les cas où il existe des transitions fréquentes entre le code managé et le code natif.

Notes

Il est recommandé de ne pas développer de nouvelles procédures stockées étendues, parce que cette fonctionnalité a été déconseillée.

Sérialisation native pour les types définis par l'utilisateur

Les types définis par l'utilisateur (UDT) sont conçus comme mécanisme d'extensibilité du système de types scalaires. SQL Server implémente un format de sérialisation pour les UDT appelé Format.Native. Pendant la compilation, la structure du type est examinée pour générer un langage MSIL personnalisé pour cette définition de type particulière.

La sérialisation native est l’implémentation par défaut pour SQL Server. La sérialisation définie par l'utilisateur appelle une méthode définie par le créateur du type pour effectuer la sérialisation. La sérialisation Format.Native doit être utilisée si possible pour de meilleures performances.

Normalisation d'UDT comparables

Les opérations relationnelles, telles que le tri et la comparaison d'UDT, fonctionnent directement sur la représentation binaire de la valeur. Cette tâche s'effectue en stockant une représentation normalisée (classement binaire) de l'état de l'UDT sur le disque.

La normalisation présente deux avantages : elle rend la comparaison considérablement moins onéreuse en évitant la construction de l'instance du type et les charges mémoire liées à l'appel de méthode ; de plus, elle crée un domaine binaire pour l'UDT, en permettant la construction d'histogrammes, d'index et d'histogrammes pour les valeurs du type. Par conséquent, les UDT normalisés offrent un profil de performance très similaire aux types intégrés natifs pour les opérations qui n'impliquent pas d'appel de méthode.

Utilisation de la mémoire évolutive

Pour que le garbage collection géré fonctionne correctement et soit correctement mis à l’échelle dans SQL Server, évitez l’allocation unique et volumineuse. Les allocations d'une taille supérieure à 88 Ko sont placées sur le tas des objets volumineux, ce qui provoque une exécution du garbage collection et une évolution bien moins performantes que nombre d'allocations plus réduites. Par exemple, si vous devez allouer un grand tableau multidimensionnel, il est préférable d'allouer un tableau en escalier.

Voir aussi

Types CLR définis par l’utilisateur