Prestaties van CLR-integratiearchitectuur
van toepassing op:SQL Server
Azure SQL Managed Instance
In dit artikel worden enkele ontwerpopties besproken die de prestaties van SQL Server-integratie verbeteren met de .NET Framework Common Language Runtime (CLR).
Het compilatieproces
Wanneer tijdens het compileren van SQL-expressies een verwijzing naar een beheerde routine wordt aangetroffen, wordt er een algemene CIL-stub (tussenliggende taal) gegenereerd. Deze stub bevat code om de routineparameters van SQL Server naar de CLR te marshalen, de functie aan te roepen en het resultaat te retourneren. Deze lijm code is gebaseerd op het type parameter en op parameterrichting (in, of verwijzing).
De lijmcode maakt typespecifieke optimalisaties mogelijk en zorgt voor een efficiënte afdwinging van SQL Server-semantiek, zoals null-baarheid, beperking van facetten, by-value en standaarduitzondering. Door code te genereren voor de exacte typen van de argumenten, voorkomt u dat u kosten voor het maken van code of wrapper-objecten (ook wel 'boksen' genoemd) over de aanroepgrens vermijdt.
De gegenereerde stub wordt vervolgens gecompileerd naar systeemeigen code en geoptimaliseerd voor de specifieke hardwarearchitectuur waarop SQL Server wordt uitgevoerd, met behulp van de Just-In-Time-compilatieservices van de CLR. De JIT-services worden aangeroepen op methodeniveau en stellen de SQL Server-hostingomgeving in staat om één compilatie-eenheid te maken die zowel SQL Server- als CLR-uitvoering omvat. Zodra de stub is gecompileerd, wordt de resulterende functiepointer de runtime-implementatie van de functie. Deze methode voor het genereren van code zorgt ervoor dat er tijdens runtime geen extra aanroepkosten zijn gerelateerd aan reflectie of toegang tot metagegevens.
Snelle overgangen tussen SQL Server en CLR
Het compilatieproces levert een functiepointer op die tijdens runtime kan worden aangeroepen vanuit systeemeigen code. Voor door de gebruiker gedefinieerde scalaire functies vindt deze functieaanroep per rij plaats. Om de kosten van de overgang tussen SQL Server en de CLR te minimaliseren, hebben instructies die beheerde aanroep bevatten een opstartstap om het doeltoepassingsdomein te identificeren. Deze identificatiestap vermindert de kosten van de overgang voor elke rij.
Prestatieoverwegingen
In de volgende sectie vindt u een overzicht van prestatieoverwegingen die specifiek zijn voor CLR-integratie in SQL Server. Zie CLR-integratie gebruiken in SQL Server 2005voor meer informatie. Zie De prestaties en schaalbaarheid van .NET-toepassingen verbeterenvoor meer informatie over de prestaties van beheerde code.
Door de gebruiker gedefinieerde functies
CLR-functies profiteren van een sneller aanroeppad dan Transact-SQL door de gebruiker gedefinieerde functies. Bovendien heeft beheerde code een doorslaggevend prestatievoordeel ten opzichte van Transact-SQL in termen van procedurele code, berekening en tekenreeksmanipulatie. CLR-functies die rekenintensief zijn en die geen gegevenstoegang uitvoeren, zijn beter geschreven in beheerde code. Transact-SQL functies echter efficiënter gegevenstoegang uitvoeren dan CLR-integratie.
Door de gebruiker gedefinieerde aggregaties
Beheerde code kan aanzienlijk beter presteren dan op cursor gebaseerde aggregatie. Beheerde code voert doorgaans iets trager uit dan ingebouwde statistische SQL Server-functies. We raden u aan om deze te gebruiken als er een systeemeigen ingebouwde statistische functie bestaat. In gevallen waarin de benodigde aggregatie niet systeemeigen wordt ondersteund, kunt u een door de gebruiker gedefinieerde CLR-aggregatie overwegen voor een op cursor gebaseerde implementatie om prestatieredenen.
Functies met een streamingtabelwaarde
Toepassingen moeten vaak een tabel retourneren als gevolg van het aanroepen van een functie. Voorbeelden hiervan zijn het lezen van tabelgegevens uit een bestand als onderdeel van een importbewerking en het converteren van door komma's gescheiden waarden naar een relationele weergave. Normaal gesproken kunt u dit doen door de resultatentabel te materialiseren en in te vullen voordat deze kan worden gebruikt door de beller. De integratie van de CLR in SQL Server introduceert een nieuw uitbreidbaarheidsmechanisme dat een STVF (Streaming Table Valued Function) wordt genoemd. Beheerde STVF's presteren beter dan vergelijkbare implementaties van uitgebreide opgeslagen procedures.
STVFs zijn beheerde functies die een IEnumerable
-interface retourneren.
IEnumerable
heeft methoden om door de resultatenset te navigeren die door de STVF wordt geretourneerd. Wanneer de STVF wordt aangeroepen, wordt de geretourneerde IEnumerable
rechtstreeks verbonden met het queryplan. Het queryplan roept IEnumerable
methoden aan wanneer er rijen moeten worden opgehaald. Met dit iteratiemodel kunnen resultaten direct worden verbruikt nadat de eerste rij is geproduceerd, in plaats van te wachten totdat de hele tabel is gevuld. Het vermindert ook het geheugen dat wordt verbruikt door de functie aan te roepen aanzienlijk.
Matrices versus cursors
Wanneer Transact-SQL cursors gegevens moeten doorlopen die gemakkelijker worden uitgedrukt als een matrix, kunnen beheerde code worden gebruikt met aanzienlijke prestatieverbeteringen.
Tekenreeksgegevens
SQL Server-tekengegevens, zoals varchar, kunnen van het type SqlString
of SqlChars
in beheerde functies zijn.
SqlString
variabelen maken een exemplaar van de volledige waarde in het geheugen.
SqlChars
variabelen bieden een streaming-interface die kan worden gebruikt om betere prestaties en schaalbaarheid te bereiken door geen exemplaar van de volledige waarde in het geheugen te maken. Dit wordt belangrijk voor lob-gegevens (large object). Daarnaast kunnen server-XML-gegevens worden geopend via een streaming-interface die wordt geretourneerd door SqlXml.CreateReader()
.
CLR versus uitgebreide opgeslagen procedures
De Microsoft.SqlServer.Server
API's (Application Programming Interfaces) waarmee beheerde procedures resultatensets kunnen terugsturen naar de client, presteren beter dan de ODS-API's (Open Data Services) die worden gebruikt door uitgebreide opgeslagen procedures. Bovendien ondersteunen de System.Data.SqlServer
API's gegevenstypen zoals xml-, varchar(max), nvarchar(max)en varbinary(max), terwijl de ODS-API's niet zijn uitgebreid om deze gegevenstypen te ondersteunen.
Met beheerde code beheert SQL Server het gebruik van resources, zoals geheugen, threads en synchronisatie. Dit komt doordat de beheerde API's die deze resources beschikbaar maken, boven op sql Server-resourcebeheer worden geïmplementeerd. Omgekeerd heeft SQL Server geen weergave of controle over het resourcegebruik van de uitgebreide opgeslagen procedure. Als een uitgebreide opgeslagen procedure bijvoorbeeld te veel CPU- of geheugenbronnen verbruikt, kunt u dit niet detecteren of beheren met SQL Server. Met beheerde code kan SQL Server echter detecteren dat een bepaalde thread gedurende een lange periode niet heeft opgeleverd en vervolgens afdwingen dat de taak wordt geretourneerd, zodat andere werkzaamheden kunnen worden gepland. Het gebruik van beheerde code biedt dus betere schaalbaarheid en systeemresourcegebruik.
Beheerde code kan extra overhead opleveren die nodig is om de uitvoeringsomgeving te onderhouden en beveiligingscontroles uit te voeren. Dit is bijvoorbeeld het geval wanneer sql Server wordt uitgevoerd in SQL Server en talloze overgangen van beheerde naar systeemeigen code zijn vereist (omdat SQL Server extra onderhoud moet uitvoeren voor threadspecifieke instellingen wanneer u overstapt op systeemeigen code en terug). Uitgebreide opgeslagen procedures kunnen dus aanzienlijk beter presteren dan beheerde code die in SQL Server wordt uitgevoerd voor gevallen waarin er frequente overgangen zijn tussen beheerde en systeemeigen code.
Notitie
Ontwikkel geen nieuwe uitgebreide opgeslagen procedures, omdat deze functie is afgeschaft.
Systeemeigen serialisatie voor door de gebruiker gedefinieerde typen
Door de gebruiker gedefinieerde typen (UDT's) zijn ontworpen als een uitbreidbaarheidsmechanisme voor het scalaire typesysteem. SQL Server implementeert een serialisatie-indeling voor UDT's met de naam Format.Native
. Tijdens de compilatie wordt de structuur van het type onderzocht om CIL te genereren dat is aangepast voor die specifieke typedefinitie.
Systeemeigen serialisatie is de standaard implementatie voor SQL Server. Door de gebruiker gedefinieerde serialisatie roept een methode aan die is gedefinieerd door de auteur van het type om de serialisatie uit te voeren.
Format.Native
serialisatie moet worden gebruikt indien mogelijk voor de beste prestaties.
Normalisatie van vergelijkbare UDF's
Relationele bewerkingen, zoals het sorteren en vergelijken van UDT's, werken rechtstreeks op de binaire weergave van de waarde. Dit wordt bereikt door een genormaliseerde (binaire geordende) weergave van de status van de UDT op schijf op te slaan.
Normalisatie heeft twee voordelen:
Het maakt de vergelijkingsbewerking aanzienlijk goedkoper door de bouw van het typeexemplaren en de aanroepoverhead van de methode te vermijden.
Het maakt een binair domein voor de UDT, waardoor de constructie van histogrammen, indexen en histogrammen voor waarden van het type mogelijk is.
Genormaliseerde UDFT's hebben dus een vergelijkbaar prestatieprofiel als de systeemeigen ingebouwde typen voor bewerkingen waarvoor geen methode-aanroep is betrokken.
Schaalbaar geheugengebruik
Vermijd grote, enkelvoudige toewijzingen om beheerde garbagecollection goed uit te voeren en te schalen in SQL Server. Toewijzingen groter dan 88 kB (kB) worden geplaatst op de Grote Object Heap, waardoor garbagecollection slechter presteert en schaalt dan veel kleinere toewijzingen. Als u bijvoorbeeld een grote multidimensionale matrix wilt toewijzen, is het beter om een gelabelde (verspreide) matrix toe te wijzen.