Notre application doit fonctionner aussi bien avec une base de données Oracle ou une base de données Microsoft SQL Server. Pour faciliter cela, nous avons créé une poignée d'UDF pour homogénéiser notre syntaxe de requête. Par exemple, SQL Server a GETDATE () et Oracle a SYSDATE. Ils remplissent la même fonction mais ce sont des mots différents. Nous avons écrit un UDF wrapper appelé NOW () pour les deux plates-formes qui encapsule la syntaxe spécifique à la plate-forme appropriée dans un nom de fonction commun. Nous avons d'autres fonctions de ce type, dont certaines n'ont pratiquement rien d'autre mais n'existent que dans un but d'homogénéisation. Malheureusement, cela a un coût pour SQL Server. Les FDU scalaires en ligne font des ravages sur les performances et désactivent complètement le parallélisme. Comme alternative, nous avons écrit des fonctions d'assemblage CLR pour atteindre les mêmes objectifs. Lorsque nous avons déployé cela sur un client, il a commencé à rencontrer des blocages fréquents. Ce client particulier utilise des techniques de réplication et de haute disponibilité et je me demande s'il y a une sorte d'interaction en cours ici. Je ne comprends tout simplement pas comment l'introduction d'une fonction CLR pourrait causer des problèmes comme celui-ci. Pour référence, j'ai inclus la définition UDF scalaire d'origine ainsi que la définition CLR de remplacement en C # et la déclaration SQL correspondante. J'ai également un XML de blocage que je peux fournir si cela aide.
UDF d'origine
CREATE FUNCTION [fn].[APAD]
(
@Value VARCHAR(4000)
, @tablename VARCHAR(4000) = NULL
, @columnname VARCHAR(4000) = NULL
)
RETURNS VARCHAR(4000)
WITH SCHEMABINDING
AS
BEGIN
RETURN LTRIM(RTRIM(@Value))
END
GO
Fonction d'assemblage CLR
[SqlFunction(IsDeterministic = true)]
public static string APAD(string value, string tableName, string columnName)
{
return value?.Trim();
}
Déclaration SQL Server pour la fonction CLR
CREATE FUNCTION [fn].[APAD]
(
@Value NVARCHAR(4000),
@TableName NVARCHAR(4000),
@ColumnName NVARCHAR(4000)
) RETURNS NVARCHAR(4000)
AS
EXTERNAL NAME ASI.fn.APAD
GO
la source
Réponses:
Quelle (s) version (s) de SQL Server utilisez-vous?
Je me souviens avoir vu un léger changement de comportement dans SQL Server 2017 il n'y a pas si longtemps. Je devrai revenir en arrière et voir si je peux trouver où j'en ai pris note, mais je pense que cela avait à voir avec un verrouillage de schéma initié lors de l'accès à un objet SQLCLR.
Pendant que je recherche cela, je dirai ce qui suit concernant votre approche:
Sql*
types pour les paramètres d'entrée, les types de retour. Vous devriez utiliserSqlString
au lieu destring
.SqlString
est très similaire à une chaîne nullable (la vôtrevalue?
, mais elle comporte d'autres fonctionnalités spécifiques à SQL Server. Tous lesSql*
types ont uneValue
propriété qui renvoie le type .NET attendu (par exemple,SqlString.Value
retoursstring
,SqlInt32
retoursint
,SqlDateTime
retoursDateTime
, etc.).Je déconseille d'abord toute cette approche, que les impasses soient liées ou non. Je dis cela parce que:
VARCHAR
. Êtes-vous d'accord avec la conversion implicite de tout enNVARCHAR
puis de nouveau enVARCHAR
pour des opérations simples?NVARCHAR(4000)
etNVARCHAR(MAX)
: leMAX
type (en ayant même un seul dans la signature) fait que l'appel SQLCLR prend deux fois plus longtemps que de ne pas avoir deMAX
type dans la signature (je crois que cela tient vrai pourVARBINARY(MAX)
vsVARBINARY(4000)
aussi). Vous devez donc choisir entre:NVARCHAR(MAX)
pour avoir une API simplifiée, mais prendre le coup de performance lorsque vous utilisez 8000 octets ou moins de données de chaîne, ouMAX
types et une sans (pour quand vous êtes assuré de ne jamais dépasser 8 000 octets de données de chaîne en entrée ou en sortie). C'est l'approche que j'ai choisie pour la plupart des fonctions de ma bibliothèque SQL # : il y a uneTrim()
fonction qui a probablement un ou plusieursMAX
types, et uneTrim4k()
version qui n'a jamais deMAX
type nulle part dans le schéma de signature ou de jeu de résultats. Les versions "4k" sont absolument plus efficaces.Vous ne faites pas attention à émuler les fonctionnalités étant donné l'exemple de la question.
LTRIM
etRTRIM
ne découper que les espaces, tandis que .NETString.Trim()
supprime les espaces blancs (au moins l'espace, les tabulations et les nouvelles lignes). Par exemple:la source