Condividi tramite


Architettura di integrazione CLR - Prestazioni

Si applica a: SQL Server Istanza gestita di SQL di Azure

Questo argomento illustra alcune delle scelte di progettazione che migliorano le prestazioni dell'integrazione di Microsoft SQL Server con Microsoft .NET Framework Common Language Runtime (CLR).

Processo di compilazione

Durante la compilazione di espressioni SQL, quando viene rilevato un riferimento a una routine gestita, viene generato uno stub MSIL (Microsoft Intermediate Language). Questo stub include il codice per effettuare il marshalling dei parametri di routine da SQL Server a CLR, richiamare la funzione e restituire il risultato. Questo codice di "unione" si basa sul tipo di parametro e sulla direzione del parametro (interna, esterna o di riferimento).

Il codice glue consente ottimizzazioni specifiche del tipo e garantisce un'applicazione efficiente della semantica di SQL Server, ad esempio nullbility, constraining facet, by-value e standard exception handling. La generazione di codice apposito per i tipi degli argomenti consente di evitare i costi legati all'assegnazione forzata o alla creazione di oggetti wrapper, chiamata "boxing", all'interno dei limiti della chiamata.

Lo stub generato viene quindi compilato in codice nativo e ottimizzato per l'architettura hardware specifica in cui viene eseguito SQL Server, usando i servizi di compilazione JIT (JUST-in-time) di CLR. I servizi JIT vengono richiamati a livello di metodo e consentono all'ambiente di hosting di SQL Server di creare una singola unità di compilazione che si estende sia sull'esecuzione di SQL Server che su CLR. Dopo aver compilato lo stub, il puntatore a funzione risultante diventa l'implementazione in fase di esecuzione della funzione. Questo approccio che prevede la generazione di codice consente di evitare i costi di chiamata aggiuntivi relativi alla riflessione o all'accesso ai metadati in fase di esecuzione.

Transizioni veloci tra SQL Server e CLR

Il processo di compilazione restituisce un puntatore a funzione che può essere chiamato in fase di esecuzione dal codice nativo. Nel caso di funzioni definite dall'utente a valori scalari, questa chiamata alla funzione avviene su ogni riga. Per ridurre al minimo il costo della transizione tra SQL Server e CLR, le istruzioni che contengono qualsiasi chiamata gestita hanno un passaggio di avvio per identificare il dominio dell'applicazione di destinazione. Questo passaggio di identificazione riduce il costo della transizione per ogni riga.

Considerazioni sulle prestazioni

Di seguito sono riepilogate le considerazioni sulle prestazioni specifiche per l'integrazione con CLR in SQL Server. Per informazioni più dettagliate, vedere "Using CLR Integration in SQL Server 2005" (Uso dell'integrazione CLR in SQL Server 2005) nel sito Web MSDN. Informazioni generali sulle prestazioni del codice gestito sono disponibili in "Miglioramento delle prestazioni e della scalabilità delle applicazioni .NET" nel sito Web MSDN.

Funzioni definite dall'utente

Le funzioni CLR traggono vantaggio da un percorso di chiamata più rapido rispetto a quello delle funzioni definite dall'utente Transact-SQL. Inoltre, il codice gestito offre un vantaggio decisivo sulle prestazioni rispetto a Transact-SQL in termini di codice procedurale, calcolo e manipolazione delle stringhe. Le funzioni CLR che prevedono intense attività di calcolo e che non eseguono l'accesso ai dati vengono scritte meglio in codice gestito. Le funzioni Transact-SQL, tuttavia, eseguono l'accesso ai dati in modo più efficiente rispetto all'integrazione con CLR.

Funzioni di aggregazione definite dall'utente

Il codice gestito può determinare prestazioni notevolmente superiori rispetto all'aggregazione basata sul cursore. Il codice gestito in genere funziona leggermente più lentamente rispetto alle funzioni di aggregazione predefinite di SQL Server. Se esiste una funzione di aggregazione predefinita nativa, è consigliabile utilizzarla. Nei casi in cui l'aggregazione necessaria non è supportata a livello nativo, è opportuno utilizzare un'aggregazione definita dall'utente CLR su un'implementazione basata sul cursore per migliorare le prestazioni.

STVF (Streaming Table-Valued Function, Funzioni di flusso con valori di tabella)

Le applicazioni spesso devono restituire una tabella come risultato della chiamata di una funzione. Gli esempi includono la lettura di dati tabulari da un file nell'ambito di un'operazione di importazione e la conversione di valori delimitati da virgole in una rappresentazione relazionale. Per effettuare queste operazioni in genere è necessario materializzare e popolare la tabella dei risultati prima che possa essere utilizzata dal chiamante. L'integrazione di CLR in SQL Server introduce un nuovo meccanismo di estendibilità denominato funzione con valori di tabella di streaming (STVF). Le funzioni di flusso con valori di tabella offrono prestazioni migliori rispetto alle implementazioni delle stored procedure estese confrontabili.

Le funzioni STVFs sono funzioni gestite che restituiscono un'interfaccia IEnumerable . IEnumerable include metodi per spostarsi nel set di risultati restituito da STVF. Quando viene richiamato stvf, l'oggetto IEnumerable restituito è connesso direttamente al piano di query. Il piano di query chiama metodi IEnumerable quando deve recuperare righe. Questo modello di iterazione consente di utilizzare immediatamente i risultati subito dopo la produzione della prima riga, anziché dover attendere che venga popolata l'intera tabella. Riduce inoltre significativamente la quantità di memoria utilizzata quando si richiama la funzione.

Confronto tra matrici e cursori

Quando i cursori Transact-SQL devono attraversare i dati che sono più facilmente espressi come matrice, il codice gestito può essere usato con miglioramenti significativi delle prestazioni.

Dati di tipo stringa

I dati di tipo carattere di SQL Server, ad esempio varchar, possono essere di tipo SqlString o SqlChars nelle funzioni gestite. Le variabili SqlString creano un'istanza dell'intero valore in memoria. Le variabili SqlChars forniscono un'interfaccia di flusso che può essere utilizzata per ottenere prestazioni migliori e una maggiore scalabilità creando un'istanza dell'intero valore in memoria. Questo diventa particolarmente importante per i dati di tipo LOB. È inoltre possibile accedere ai dati XML del server tramite un'interfaccia di streaming restituita da SqlXml.CreateReader().

Confronto tra CLR e stored procedure estese

Le API Microsoft.SqlServer.Server che consentono alle procedure gestite di inviare di nuovo i set di risultati al client offrono prestazioni migliori rispetto alle API ODS (Open Data Services) utilizzate dalle stored procedure estese. Inoltre, le API System.Data.SqlServer supportano tipi di dati come xml, varchar(max), nvarchar(max)e varbinary(max), introdotti in SQL Server 2005 (9.x), mentre le API ODS non sono state estese per supportare i nuovi tipi di dati.

Con il codice gestito, SQL Server gestisce l'uso di risorse come memoria, thread e sincronizzazione. Ciò avviene perché le API gestite che espongono queste risorse vengono implementate in gestione risorse di SQL Server. Al contrario, SQL Server non ha alcuna visualizzazione o controllo sull'utilizzo delle risorse della stored procedure estesa. Ad esempio, se una stored procedure estesa utilizza una quantità eccessiva di CPU o risorse di memoria, non è possibile rilevare o controllare questa operazione con SQL Server. Con il codice gestito, tuttavia, SQL Server può rilevare che un determinato thread non è stato restituito per un lungo periodo di tempo e quindi forzare la resa dell'attività in modo che altri lavori possano essere pianificati. Di conseguenza, l'utilizzo di codice gestito offre una maggiore scalabilità e un miglior utilizzo delle risorse di sistema.

Il codice gestito può determinare un overhead aggiuntivo, necessario per gestire l'ambiente di esecuzione ed eseguire controlli di sicurezza. Questo è il caso, ad esempio, quando si esegue all'interno di SQL Server e sono necessarie numerose transizioni dal codice gestito al codice nativo (perché SQL Server deve eseguire operazioni di manutenzione aggiuntive sulle impostazioni specifiche del thread quando si passa al codice nativo e viceverso). Di conseguenza, le stored procedure estese possono migliorare notevolmente il codice gestito in esecuzione all'interno di SQL Server per i casi in cui sono presenti frequenti transizioni tra codice gestito e nativo.

Nota

È consigliabile non sviluppare nuove stored procedure estese, in quanto questa caratteristica è deprecata.

Serializzazione nativa per i tipi definiti dall'utente

I tipi definiti dall'utente sono progettati come un meccanismo di extensibility per il sistema di tipo scalare. SQL Server implementa un formato di serializzazione per i tipi definiti dall'utente denominati Format.Native. Durante la compilazione, la struttura del tipo viene esaminata per generare un codice MSIL personalizzato per la definizione del tipo specifico.

La serializzazione nativa è l'implementazione predefinita per SQL Server. La serializzazione definita dall'utente richiama un metodo definito dall'autore del tipo per eseguire la serializzazione. La serializzazione Format.Native deve essere usata quando possibile per ottenere prestazioni ottimali.

Normalizzazione dei tipi definiti dall'utente confrontabili

Le operazioni relazionali, ad esempio l'ordinamento e il confronto dei tipi definiti dall'utente, agiscono direttamente sulla rappresentazione binaria del valore. A tale scopo, è necessario archiviare una rappresentazione normalizzata (con ordinamento binario) dello stato del tipo definito dall'utente su disco.

La normalizzazione presenta due vantaggi: rende l'operazione di confronto molto meno costosa evitando la costruzione dell'istanza del tipo e l'overhead della chiamata al metodo e crea un dominio binario per il tipo definito dall'utente, consentendo la costruzione di istogrammi, indici e istogrammi per i valori del tipo. Di conseguenza, i tipi definiti dall'utente normalizzati offrono prestazioni molto simili ai tipi predefiniti nativi per operazioni che non comportano chiamate al metodo.

Utilizzo della memoria scalabile

Per consentire l'esecuzione e la scalabilità ottimale di Garbage Collection gestita in SQL Server, evitare allocazioni singole e di grandi dimensioni. Le allocazioni di dimensioni maggiori di 88 kilobyte (KB) vengono inserite nell'heap oggetti grandi che determina prestazioni e scalabilità nettamente inferiori rispetto ad allocazioni più piccole. Se ad esempio è necessario allocare una matrice multidimensionale di dimensioni elevate, è preferibile allocare una matrice di matrici (a dispersione).

Vedi anche

Tipi CLR definiti dall'utente