Teilen über


CLR-Integrationsarchitektur: Leistung

Gilt für: SQL Server Azure SQL verwaltete Instanz

In diesem Thema werden einige der Designoptionen erläutert, die die Leistung der Microsoft SQL Server-Integration in die Common Language Runtime (CLR) von Microsoft .NET Framework verbessern.

Der Kompilierungsprozess

Bei der Kompilierung von SQL-Ausdrücken wird beim Auftreten eines Verweises auf eine verwaltete Routine ein MSIL-Stub (Microsoft Intermediate Language) generiert. Dieser Stub enthält Code, um die Routineparameter von SQL Server an die CLR zu marshallen, die Funktion aufzurufen und das Ergebnis zurückzugeben. Dieser "Verbindungscode" basiert auf dem Parametertyp und der Parameterrichtung (IN, OUT oder Verweis).

Der Klebecode ermöglicht typspezifische Optimierungen und gewährleistet eine effiziente Erzwingung der SQL Server-Semantik, z. B. Nullierbarkeit, Einschränken von Facets, Nachwert- und Standard-Ausnahmebehandlung. Durch die Codegenerierung für genaue Argumenttypen vermeiden Sie Kosten für Typenumwandlung und die Erstellung von Wrapperobjekten ("Boxing" genannt) über die Aufrufgrenze hinweg.

Der generierte Stub wird dann in systemeigenem Code kompiliert und für die spezielle Hardwarearchitektur optimiert, auf der SQL Server ausgeführt wird, wobei die JIT-Kompilierungsdienste (just-in-time) der CLR verwendet werden. Die JIT-Dienste werden auf Methodenebene aufgerufen und ermöglichen es der SQL Server-Hostingumgebung, eine einzelne Kompilierungseinheit zu erstellen, die sowohl sql Server- als auch CLR-Ausführung umfasst. Sobald der Stub kompiliert ist, wird der resultierende Funktionszeiger zur Laufzeitimplementierung der Funktion. Dieses Codegenerierungsverfahren stellt sicher, dass keine zusätzlichen Aufrufkosten durch Reflexion oder Metadatenzugriff zur Laufzeit entstehen.

Schnelle Übergänge zwischen SQL Server und CLR

Der Kompilierungsprozess erzeugt einen Funktionszeiger, der zur Laufzeit über systemeigenen Code aufgerufen werden kann. Bei benutzerdefinierten Skalarwertfunktionen erfolgt dieser Funktionsaufruf auf Zeilenbasis. Um die Kosten für den Übergang zwischen SQL Server und CLR zu minimieren, weisen Anweisungen, die einen verwalteten Aufruf enthalten, einen Startschritt auf, um die Zielanwendungsdomäne zu identifizieren. Dieser Identifizierungsschritt reduziert die Kosten für den Übergang der einzelnen Zeilen.

Überlegungen zur Leistung

Im Folgenden werden Leistungsüberlegungen zusammengefasst, die für die CLR-Integration in SQL Server spezifisch sind. Ausführlichere Informationen finden Sie unter "Verwenden der CLR-Integration in SQL Server 2005" auf der MSDN-Website. Allgemeine Informationen zur Leistung von verwaltetem Code finden Sie auf der MSDN-Website unter "Verbessern der Leistung und Skalierbarkeit von .NET-Anwendungen".

Benutzerdefinierte Funktionen

CLR-Funktionen profitieren von einem schnelleren Aufrufpfad als von benutzerdefinierten Transact-SQL-Funktionen. Darüber hinaus hat verwalteter Code einen entscheidenden Leistungsvorteil gegenüber Transact-SQL im Hinblick auf prozeduralen Code, Berechnung und Zeichenfolgenmanipulation. Rechenintensive CLR-Funktionen, die keinen Datenzugriff ausführen, sollten bevorzugt in verwaltetem Code geschrieben werden. Transact-SQL-Funktionen führen jedoch den Datenzugriff effizienter aus als die CLR-Integration.

Benutzerdefinierte Aggregate

Verwalteter Code ist deutlich leistungsfähiger als die cursorbasierte Aggregation. Verwalteter Code führt in der Regel etwas langsamer aus als integrierte SQL Server-Aggregatfunktionen. Wir empfehlen daher, eine systemeigene integrierte Aggregatfunktion zu verwenden, sofern sie zur Verfügung steht. In Fällen, in denen die benötigte Aggregation nicht vom System unterstützt wird, sollten Sie aus Gründen der Leistungsfähigkeit ein CLR-benutzerdefiniertes Aggregat einer cursorbasierten Implementierung den Vorzug geben.

Streaming-Tabellenwertfunktionen

Anwendungen müssen oft als Reaktion auf einen Funktionsaufruf eine Tabelle als Ergebnis zurückgeben. Beispiele dafür sind das Lesen von Tabellendaten aus einer Datei als Teil eines Importvorgangs oder die Konvertierung von durch Trennzeichen getrennten Werte in eine relationale Darstellung. In der Regel erreichen Sie dies durch Materialisieren und Auffüllen der Ergebnistabelle, bevor sie vom Aufrufer verwendet werden kann. Die Integration der CLR in SQL Server führt einen neuen Erweiterbarkeitsmechanismus ein, der als Streamingtabellenwertfunktion (STVF) bezeichnet wird. Verwaltete STVF sind leistungsfähiger als vergleichbare Implementierungen mit erweiterten gespeicherten Prozeduren.

STVFs sind verwaltete Funktionen, die eine IEnumerable-Schnittstelle zurückgeben. IEnumerable verfügt über Methoden zum Navigieren in dem vom STVF zurückgegebenen Resultset. Wenn der STVF aufgerufen wird, wird die zurückgegebene IEnumerable direkt mit dem Abfrageplan verbunden. Der Abfrageplan ruft IEnumerable-Methoden auf, wenn zeilen abgerufen werden müssen. Dieses Iterationsmodell ermöglicht es, dass Ergebnisse sofort nach Abruf der ersten Zeile verarbeitet werden. Es muss nicht gewartet werden, bis die gesamte Tabelle aufgefüllt ist. Dadurch wird zudem der durch den Funktionsaufruf benötigte Arbeitsspeicher stark reduziert.

Arrays oder Cursor

Wenn Transact-SQL-Cursor Daten durchlaufen müssen, die einfacher als Array ausgedrückt werden, kann verwalteter Code mit erheblichen Leistungsgewinnen verwendet werden.

Zeichenfolgendaten

SQL Server-Zeichendaten, z . B. Varchar, können vom Typ "SqlString" oder "SqlChars" in verwalteten Funktionen sein. SqlString-Variablen erstellen im Arbeitsspeicher eine Instanz des gesamten Werts. SqlChars-Variablen stellen eine Streamingschnittstelle bereit, mit der eine höhere Leistung und bessere Skalierbarkeit erreicht wird, die jedoch nicht zum Erstellen einer Instanz des gesamten Werts im Arbeitsspeicher verwendet werden kann. Dies ist besonders für Daten großer Objekte (Large Objects, LOB) wichtig. Darüber hinaus können Server-XML-Daten über eine Streamingschnittstelle aufgerufen werden, die von SqlXml.CreateReader()zurückgegeben wird.

CLR und erweiterte gespeicherte Prozeduren im Vergleich

Die Microsoft.SqlServer.Server-APIs (Application Programming Interfaces), die es verwalteten Prozeduren ermöglichen, Resultsets zurück an den Client zu senden, sind leistungsfähiger als die von erweiterten gespeicherten Prozeduren verwendeten Open Data Services(ODS)-APIs. Darüber hinaus unterstützen die System.Data.SqlServer-APIs Datentypen wie xml, varchar(max), nvarchar(max) und varbinary(max), eingeführt in SQL Server 2005 (9.x), während die ODS-APIs nicht erweitert wurden, um die neuen Datentypen zu unterstützen.

Mit verwaltetem Code verwaltet SQL Server die Verwendung von Ressourcen wie Arbeitsspeicher, Threads und Synchronisierung. Dies liegt daran, dass die verwalteten APIs, die diese Ressourcen verfügbar machen, über dem SQL Server-Ressourcen-Manager implementiert werden. Umgekehrt hat SQL Server keine Ansicht oder Kontrolle über die Ressourcennutzung der erweiterten gespeicherten Prozedur. Wenn eine erweiterte gespeicherte Prozedur z. B. zu viel CPU- oder Arbeitsspeicherressourcen verbraucht, gibt es keine Möglichkeit, dies mit SQL Server zu erkennen oder zu steuern. Mit verwaltetem Code kann SQL Server jedoch erkennen, dass ein bestimmter Thread nicht für einen längeren Zeitraum zurückgegeben wurde, und dann erzwingt die Aufgabe, sodass andere Arbeiten geplant werden können. Infolgedessen kann mit verwaltetem Code eine bessere Skalierbarkeit und Systemressourcenverwendung erreicht werden.

Durch verwalteten Code können möglicherweise zusätzliche Kosten für die Aufrechterhaltung der Ausführungsumgebung sowie die Durchführung von Sicherheitsüberprüfungen entstehen. Dies ist beispielsweise der Fall, wenn sie in SQL Server ausgeführt wird und zahlreiche Übergänge von verwaltetem zu systemeigenem Code erforderlich sind (da SQL Server zusätzliche Wartung für threadspezifische Einstellungen ausführen muss, wenn sie in systemeigenem Code und zurück wechseln). Daher können erweiterte gespeicherte Prozeduren verwalteten Code, der in SQL Server ausgeführt wird, erheblich übersteigen, wenn es häufige Übergänge zwischen verwaltetem und systemeigenem Code gibt.

Hinweis

Es wird jedoch empfohlen, keine neuen erweiterten gespeicherten Prozeduren zu entwickeln, da diese Funktion veraltet ist.

Systemeigene Serialisierung für benutzerdefinierte Typen

Benutzerdefinierte Typen (UDTs) wurden als Erweiterungsmechanismus für das Skalartypsystem entworfen. SQL Server implementiert ein Serialisierungsformat für UDTs namens "Format.Native". Während der Kompilierung wird die Struktur des Typs zur Generierung von MSIL geprüft, das für die betreffende Typdefinition angepasst wird.

Native Serialisierung ist die Standardimplementierung für SQL Server. Die benutzerdefinierte Serialisierung ruft eine Methode auf, die vom Typautor für die Durchführung der Serialisierung definiert wurde. Format.Native Serialisierung sollte verwendet werden, wenn möglich, um eine optimale Leistung zu erzielen.

Normalisierung vergleichbarer UDTs

Relationale Vorgänge, z. B. die Sortierung und das Vergleichen von UDTs, verwenden direkt die binäre Darstellung des Werts. Zu diesem Zweck wird eine normalisierte (binär sortierte) Darstellung des UDT-Zustands auf Festplatte gespeichert.

Normalisierungen bieten zwei Vorteile: Erstens verringern sie den Arbeitsaufwand für den Vergleich erheblich, indem sie die Konstruktion der Typinstanz und die Kosten für den Methodenaufruf vermeiden. Zweitens erstellen sie eine binäre Domäne für den UDT und ermöglichen so die Konstruktion von Histogrammen, Indizes und Histogrammen für Werte des Typs. Daher haben normalisierte UDTs ein Leistungsprofil, das dem von systemeigenen integrierten Typen sehr ähnlich ist, wenn es sich um Vorgänge handelt, die keinen Methodenaufruf erfordern.

Skalierbare Speicherverwendung

Um die verwaltete Garbage Collection in SQL Server gut auszuführen und zu skalieren, vermeiden Sie eine große, einzelne Zuordnung. Zuteilungen, die größer als 88 Kilobytes (KB) sind, werden im Objektheap für große Objekte positioniert. Das führt dazu, dass die automatische Speicherbereinigung schlechter ausgeführt und skaliert wird als bei vielen kleinen Zuteilungen. Wenn Sie beispielsweise ein großes mehrdimensionales Array zuteilen müssen, empfiehlt es sich, ein verzweigtes Array zuzuteilen.

Weitere Informationen

Benutzerdefinierte CLR-Typen