Unsere Anwendung muss mit einer Oracle-Datenbank oder einer Microsoft SQL Server-Datenbank gleich gut funktionieren. Um dies zu vereinfachen, haben wir eine Handvoll UDFs erstellt, um unsere Abfragesyntax zu homogenisieren. Beispielsweise hat SQL Server GETDATE () und Oracle SYSDATE. Sie erfüllen dieselbe Funktion, sind jedoch unterschiedliche Wörter. Wir haben für beide Plattformen eine Wrapper-UDF namens NOW () geschrieben, die die relevante plattformspezifische Syntax in einen gemeinsamen Funktionsnamen einschließt. Wir haben andere solche Funktionen, von denen einige im Wesentlichen nichts anderes tun, als nur zur Homogenisierung zu existieren. Leider hat dies Kosten für SQL Server. Inline-skalare UDFs beeinträchtigen die Leistung und deaktivieren die Parallelität vollständig. Als Alternative haben wir CLR-Assembly-Funktionen geschrieben, um dieselben Ziele zu erreichen. Als wir dies für einen Client bereitstellten, traten häufig Deadlocks auf. Dieser spezielle Client verwendet Replikations- und Hochverfügbarkeitstechniken und ich frage mich, ob hier irgendeine Art von Interaktion stattfindet. Ich verstehe nur nicht, wie die Einführung einer CLR-Funktion solche Probleme verursachen würde. Als Referenz habe ich die ursprüngliche skalare UDF-Definition sowie die Ersatz-CLR-Definition in C # und die SQL-Deklaration dafür aufgenommen. Ich habe auch Deadlock-XML, das ich bereitstellen kann, wenn das hilft.
Original UDF
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
CLR-Montagefunktion
[SqlFunction(IsDeterministic = true)]
public static string APAD(string value, string tableName, string columnName)
{
return value?.Trim();
}
SQL Server-Deklaration für die CLR-Funktion
CREATE FUNCTION [fn].[APAD]
(
@Value NVARCHAR(4000),
@TableName NVARCHAR(4000),
@ColumnName NVARCHAR(4000)
) RETURNS NVARCHAR(4000)
AS
EXTERNAL NAME ASI.fn.APAD
GO
quelle
Antworten:
Welche Version (en) von SQL Server verwenden Sie?
Ich erinnere mich an eine leichte Änderung des Verhaltens in SQL Server 2017 vor nicht allzu langer Zeit. Ich muss zurückgehen und nachsehen, ob ich herausfinden kann, wo ich es notiert habe, aber ich denke, es hat damit zu tun, dass beim Zugriff auf ein SQLCLR-Objekt eine Schemasperre initiiert wurde.
Während ich danach suche, werde ich Folgendes zu Ihrem Ansatz sagen:
Sql*
Typen für Eingabeparameter, Rückgabetypen. Sie solltenSqlString
anstelle von verwendenstring
.SqlString
ist einer nullbaren Zeichenfolge sehr ähnlich (Ihrevalue?
, aber es sind andere Funktionen integriert, die SQL Server-spezifisch sind. AlleSql*
Typen haben eineValue
Eigenschaft, die den erwarteten .NET-TypSqlString.Value
zurückgibt (z. B. Rückgabenstring
,SqlInt32
Rückgabenint
,SqlDateTime
RückgabenDateTime
usw.).Ich würde zunächst gegen diesen gesamten Ansatz empfehlen, ob die Deadlocks zusammenhängen oder nicht. Ich sage das, weil:
VARCHAR
. Können Sie implizit alles für einfache Operationen inNVARCHAR
und dann wieder zurück konvertierenVARCHAR
?NVARCHAR(4000)
undNVARCHAR(MAX)
: DerMAX
Typ (der nur einen einzigen in der Signatur enthält) lässt den SQLCLR-Aufruf doppelt so lange dauern wie keinenMAX
Typ in der Signatur (ich glaube, dies gilt gilt auch fürVARBINARY(MAX)
vsVARBINARY(4000)
). Sie müssen sich also entscheiden zwischen:NVARCHAR(MAX)
, um eine vereinfachte API zu haben, aber nehmen Sie den Leistungseinbruch, wenn Sie 8000 Byte oder weniger Zeichenfolgendaten verwenden, oderMAX
Typ und eine ohne (wenn Sie garantiert nie mehr als 8000 Byte Zeichenfolgendaten ein- oder ausgeben). Dies ist der Ansatz, den ich für die meisten Funktionen in meiner SQL # -Bibliothek gewählt habe: Es gibt eineTrim()
Funktion, die wahrscheinlich einen oder mehrereMAX
Typen hat, und eineTrim4k()
Version, die niemals einenMAX
Typ im Signatur- oder Ergebnismengenschema hat. Die "4k" -Versionen sind absolut effizienter.Sie achten nicht darauf, die Funktionalität anhand des Beispiels in der Frage zu emulieren.
LTRIM
undRTRIM
nur LeerzeichenString.Trim()
zuschneiden , während .NET Leerzeichen trimmt (mindestens Leerzeichen, Tabulatoren und Zeilenumbrüche). Zum Beispiel:quelle