Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Componenti interni di SQL Server:pianificare la memorizzazione nella cache Pt. I – Piani di riutilizzo

SQL Server esiste da oltre 30 anni e lavoro con SQL Server da quasi lo stesso tempo. Ho visto molti cambiamenti nel corso degli anni (e decenni!) e delle versioni di questo incredibile prodotto. In questi post condividerò con te come considero alcune delle funzionalità o aspetti di SQL Server, a volte insieme a un po' di prospettiva storica.

Dai un'occhiata ai recenti blog di Kalen sugli operatori problematici qui.

La creazione di piani per la diagnostica del server SQL può essere costosa, poiché Query Optimizer deve essere in grado di trovare un buon piano per qualsiasi query legale inviata. L'ottimizzatore valuta più ordini di unione, più indici. e vari tipi di algoritmi di join e raggruppamento, a seconda della query e delle tabelle coinvolte. Se la stessa query viene rieseguita, SQL Server può risparmiare molte risorse riutilizzando un piano esistente. Ma non è sempre possibile riutilizzare un piano esistente e non è sempre una buona cosa farlo. Nei prossimi due articoli, vedremo quando un piano viene riutilizzato e quando viene ricompilato.

Per prima cosa, esamineremo le diverse tipologie di piani e la visualizzazione dei metadati che utilizzo più spesso per vedere cosa c'è nella cache dei miei piani. Ho scritto una mia vista che fornisce le informazioni che trovo più utili più spesso. SQL Server memorizza nella cache sei diversi tipi di piani di query, ma in genere solo due vengono utilizzati per l'ottimizzazione della cache dei piani. Questi sono PIANO COMPILATO e STUB PIANO COMPILATO. La mia vista filtra tutti tranne questi due tipi di oggetti cache. I PIANI COMPILATI sono disponibili in tre varietà:AD HOC, PREPARED e PROC. Commenterò tutti e tre i tipi.

Anche se stiamo solo esaminando PIANI COMPILATI, ci sono ancora molti piani nella cache che di solito devono essere ignorati, poiché sono generati da SQL Server stesso. Questi includono piani per la ricerca di filestream o indici di ricerca full-text o query interne che funzionano con OLTP in memoria. Quindi, la mia vista aggiunge filtri per cercare di eliminare la maggior parte dei piani che non mi interessano. Puoi scaricare uno script per creare questa vista, chiamato sp_cacheobjects , da qui.

Anche con tutti i filtri utilizzati dalla mia vista, ci sono ancora alcune delle query interne di SQL Server nella cache; Di solito svuoto frequentemente la cache del piano durante i test in quest'area. Il modo più semplice per cancellare TUTTI i piani dalla cache è con il comando:DBCC FREEPROCCACHE.

Piani compilati ad hoc

Il tipo più semplice di piano è Adhoc. Viene utilizzato per query di base che non rientrano in un'altra categoria. Se hai scaricato il mio script e creato la mia vista sp_cacheobjects, puoi eseguire quanto segue. Qualsiasi versione del database AdventureWorks dovrebbe funzionare. Questo script crea una copia di una tabella e crea un paio di indici univoci su di essa. Massaggia anche l'importo del totale parziale per rimuovere eventuali cifre decimali.

USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS newsales;
GO
-- Make a copy of the Sales.SalesOrderHeader table
SELECT * INTO dbo.newsales
FROM Sales.SalesOrderHeader;
GO
UPDATE dbo.newsales
SET SubTotal = cast(cast(SubTotal as int) as money);
GO
CREATE UNIQUE index newsales_ident
    ON newsales(SalesOrderID);
GO
CREATE INDEX IX_Sales_SubTotal ON newsales(SubTotal);
GO
-- Adhoc query plan reuse
DBCC FREEPROCCACHE;
GO
-- adhoc query
SELECT * FROM dbo.newsales
WHERE SubTotal = 4;
GO
SELECT * FROM sp_cacheobjects;
GO

Nel mio output, vedi due piani Adhoc. Uno è per la dichiarazione SELECT dal newssale tabella e l'altro è per SELECT dai miei sp_cacheobjects Visualizza. Poiché il piano è memorizzato nella cache, se la stessa query ESATTA viene eseguita di nuovo, lo stesso piano può essere riutilizzato e vedrai gli usecounts aumento di valore. Tuttavia, c'è un problema. Affinché un piano Adhoc possa essere riutilizzato, la stringa SQL deve essere assolutamente identica. Se si modificano caratteri nell'SQL, la query non viene riconosciuta come la stessa query e viene generato un nuovo piano. Se aggiungo anche uno spazio, includo il commento o una nuova interruzione di riga, non è la stessa stringa. Se cambio il caso, significa che ci sono diversi valori di codice ASCII, quindi non la stessa stringa.

Puoi provarlo tu stesso eseguendo diverse varianti della mia prima istruzione SELECT dalle newssales tavolo. Vedrai una riga diversa nella cache per ognuno. Dopo aver eseguito diverse varianti, modificando il numero che stavo cercando, modificando il caso, aggiungendo il commento e una nuova riga, vedo quanto segue nella cache. Il SELECT dal mio punto di vista viene riutilizzato, ma tutto il resto ha un usecounts valore di 1.

Un requisito aggiuntivo per il riutilizzo del piano di query Adhoc è che la sessione che esegue la query deve avere le stesse opzioni SET attive . C'è un'altra colonna nell'output che puoi vedere a destra del testo della query, chiamata SETOPTS. Questa è una stringa di bit con un bit per ciascuna opzione SET rilevante. Se modifichi una delle opzioni, ad esempio, SET ANSI_NULLS OFF, la stringa di bit cambierà e lo stesso piano con la stringa di bit originale non potrà essere riutilizzato.

Piani compilati preparati

Il secondo tipo di piano compilato nella cache è un piano PREPARATO. Se la tua richiesta soddisfa un determinato insieme di requisiti. In realtà può essere parametrizzato automaticamente. Viene visualizzato nei metadati come PREPARED e la stringa SQL mostra un indicatore di parametro. Ecco un esempio:

Il piano PREPARATO mostra l'indicatore del parametro come @1 e non include il valore effettivo. Si noti che esiste una riga per una query ADHOC con un valore effettivo di 5555, ma in realtà è solo una "shell" della query reale. Non memorizza nella cache l'intero piano, ma solo la query e alcuni dettagli identificativi, per aiutare il Query Processor a trovare il piano parametrizzato nella cache. Nota la dimensione (pagesused ) è molto più piccolo del piano PREPARED.

La modalità di parametrizzazione predefinita, denominata parametrizzazione SEMPLICE, è estremamente rigorosa su quali piani possono essere parametrizzati. In realtà è solo la query più semplice parametrizzabile per impostazione predefinita. Le query che contengono JOIN, GROUP BY, OR e molti altri costrutti di query relativamente comuni impediscono la parametrizzazione di una query. Oltre a non avere nessuno di questi costrutti, la cosa più importante per la parametrizzazione SIMPLE è che la query sia SAFE. Ciò significa che esiste un solo piano possibile, indipendentemente dai valori passati per qualsiasi parametro. (Naturalmente, anche una query senza parametri potrebbe essere SICURA.) La mia query cerca una corrispondenza esatta nella colonna SalesOrderID , che contiene un indice univoco. Quindi l'indice non cluster esistente potrebbe essere utilizzato per trovare qualsiasi riga corrispondente. Indipendentemente dal valore che utilizzo, 55555 o qualcos'altro, non ci sarà mai più di una riga, il che significa che il piano sarà comunque valido.

Nel mio esempio di piano di query ad hoc, stavo cercando valori corrispondenti per SubTotal . Alcuni SubTotale i valori si verificano alcune volte o per niente, quindi un indice non cluster sarebbe buono. Ma altri valori potrebbero verificarsi molte volte, quindi l'indice NON sarebbe utile. Pertanto, il piano di query non è SICURO e la query non può essere parametrizzata. Ecco perché abbiamo visto un piano Adhoc per il mio primo esempio.

SE hai query con JOIN o altri costrutti non consentiti, puoi indicare a SQL Server di essere più aggressivo nella parametrizzazione modificando un'opzione del database:

ALTER DATABASE AdventureWorks2016 SET parameterization FORCED;
GO

L'impostazione del database sulla parametrizzazione FORCED significa che SQL Server parametrizzerà molte più query, comprese quelle con JOIN, GROUP BY, OR e così via. Ma significa anche che SQL Server può parametrizzare una query che non è SICURA. Potrebbe creare un piano valido quando vengono restituite solo poche righe e quindi riutilizzare il piano quando vengono restituite molte righe. Questo può portare a prestazioni molto non ottimali.

Un'ultima opzione per un piano preparato è quando si prepara esplicitamente un piano. Questo comportamento viene in genere richiamato tramite un'applicazione con SQLPrepare e SQLExecute API. Specificare qual è la query con i contrassegni dei parametri, specificare i tipi di dati e specificare i valori specifici da utilizzare. La stessa query può quindi essere eseguita di nuovo con valori specifici diversi e verrà utilizzato il piano esistente. Sebbene l'utilizzo di piani preparati in modo esplicito possa essere possibile per quei casi in cui SQL Server non sta parametrizzando e lo si desidera, non impedisce a SQL Server di usare un piano NON valido per i parametri successivi. Devi testare le tue query con molti valori di input diversi e assicurarti di ottenere le prestazioni previste se e quando un piano viene riutilizzato.

I metadati (ad es. i miei sp_cacheobjects vista) mostra solo PREPARATO per tutti e tre i tipi di piani:autoparametrizzazione FORZATA e SEMPLICE e parametrizzazione ESPLICITA.

Piani compilati da Proc

L'ultimo objtype il valore per i piani compilati è per una stored procedure, che viene visualizzata come Proc. Quando possibile, le stored procedure sono la scelta migliore per il codice riutilizzabile, grazie alla loro facilità di gestione dal server stesso, ma ciò non significa che garantiscano sempre le migliori prestazioni. Proprio come usando l'opzione di parametrizzazione FORCED (e anche la parametrizzazione esplicita), le procedure memorizzate usano lo "sniffing dei parametri". Ciò significa che il primo valore del parametro passato determina il piano. Se le esecuzioni successive funzionano bene con lo stesso piano, lo sniffing dei parametri non è un problema e può effettivamente essere vantaggioso perché ci fa risparmiare il costo della ricompilazione e della riottimizzazione. Tuttavia, se le esecuzioni successive con valori diversi non dovessero utilizzare il piano originale, allora abbiamo un problema. Ti mostrerò un esempio di sniffing dei parametri che causa un problema

Creerò una stored procedure basata sulle newssales tabella che abbiamo usato in precedenza. La procedura avrà un'unica query, che filtra in base a SalesOrderID colonna, su cui abbiamo costruito un indice non cluster. La query sarà basata su una disuguaglianza, quindi per alcuni valori la query può restituire solo poche righe e utilizzare l'indice e, per altri valori, la query può restituire MOLTE righe. In altre parole, la query non è SICURA.

USE AdventureWorks2016;
GO
DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

Userò l'opzione SET STATISTICS IO ON per vedere quanto lavoro viene svolto quando la procedura viene eseguita. Innanzitutto, lo eseguirò con un parametro che restituisce solo poche righe:

SET STATISTICS IO ON
GO
EXEC get_sales_range 43700;
GO

Il valore STATISTICS IO segnala che sono state necessarie 43 letture logiche per restituire 41 righe. Questo è normale per un indice non cluster. Ora eseguiamo di nuovo la procedura con un valore molto più grande.

EXEC get_sales_range 66666;
GO
SELECT * FROM sp_cacheobjects;
GO
This time, we see that SQL Server used a whole lot more reads:

In effetti, una scansione della tabella sulle newssales la tabella richiede solo 843 letture, quindi si tratta di prestazioni di gran lunga peggiori di una scansione della tabella. Gli sp_cacheobjects view ci mostra che il piano PROC è stato riutilizzato per questa seconda esecuzione. Questo è un esempio di quando lo sniffing dei parametri NON è una buona cosa.

Quindi, cosa possiamo fare quando lo sniffing dei parametri è un problema? Nel prossimo post, ti dirò quando SQL Server presenta un nuovo piano e non riutilizza quelli vecchi. Vedremo come forzare (o incoraggiare) la ricompilazione e, inoltre, vedremo quando SQL Server ricompila automaticamente le tue query.

Spotlight Cloud può rivoluzionare il monitoraggio delle prestazioni e la diagnostica del server SQL. Inizia con la tua prova gratuita utilizzando il link qui sotto: