In questo articolo esamineremo le configurazioni con ambito database e la correzione automatica del piano di SQL Server 2017. Microsoft ha aggiunto nuove funzionalità a SQL Server 2017 che hanno migliorato le prestazioni delle query.
Le prestazioni delle query di SQL Server sono correlate alla qualità e all'accuratezza del piano di esecuzione. Quando eseguiamo una query, Query Optimizer analizza molti piani di esecuzione e quindi decide il piano di esecuzione della query ottimale.
Stima della cardinalità dell'eredità: Lo stimatore di cardinalità prevede il numero di righe restituite dalla query e determina l'allocazione di memoria della query.
In SQL Server 2017, la versione predefinita del modello di stima della cardinalità è 14.0, ma se si desidera utilizzare la versione precedente 7.0 dello strumento per la stima della cardinalità, è possibile farlo modificando l'opzione di stima della cardinalità legacy in Configurazioni con ambito database sezione.
Il valore predefinito della stima della cardinalità legacy è OFF. Pertanto, se desideri utilizzare la versione precedente, devi attivarla.
In alternativa, puoi modificare questa proprietà in T-SQL.
ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = OFF|ON;
Tuttavia, se abiliti questa impostazione, influirà su tutte le query. Di conseguenza, ciò potrebbe danneggiare le prestazioni della query. Per evitarlo, puoi utilizzare il suggerimento FORCE_LEGACY_CARDINALITY_ESTIMATION.
Quando eseguiamo questa query nel database WideWorldImporters, utilizzerà automaticamente una nuova versione della stima della cardinalità.
SELECT [o].[CustomerID], o.LastEditedBy , [o].[OrderDate] FROM Sales.Orders o WHERE [o].[OrderDate] >= '20140101'
Quando aggiungiamo FORCE_LEGACY_CARDINALITY_ESTIMATION alla query, Query Optimizer utilizzerà la versione precedente o meno recente della stima della cardinalità.
MAXDOP : possiamo impostare il massimo grado di parallelismo per un singolo database. Prima che questa funzionalità fosse creata, potevamo solo configurare il livello del server MAXDOP.
L'hint di query MAXDOP ci consente di eseguire query in parallelo.
ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 4; GO
Sniffing dei parametri: Quando il tempo di esecuzione di una query cambia drasticamente e questa modifica è correlata al parametro della query, si parla di sniffing del parametro.
Ora creeremo una stored procedure nel database AdventureWorks. Invieremo parametri diversi e confronteremo i piani di esecuzione.
DROP PROCEDURE IF EXISTS Get_Orders GO CREATE PROCEDURE Get_Orderes @ProductID INT AS SELECT SalesOrderDetailID, OrderQty FROM Sales.SalesOrderDetail WHERE ProductID = @ProductID; GO /******* Don t use this script in production servers! *******/ DBCC FREEPROCCACHE --Query Mars EXEC Get_OrderID_OrderQty @ProductID=870 DBCC FREEPROCCACHE --Query Venus EXEC Get_OrderID_OrderQty @ProductID=897
Come mostrato nell'immagine seguente, SQL Server genera un piano di esecuzione diverso per la stessa query. Il piano di esecuzione di Query Mars consiglia un indice. Il parametro query modifica il piano di esecuzione ottimale.
Esegui questa query e guarda i piani di esecuzione.
DBCC FREEPROCCACHE --Query Mars EXEC Get_OrderID_OrderQty @ProductID=870 --Query Venus EXEC Get_OrderID_OrderQty @ProductID=897
Il piano di esecuzione di Query Venus è lo stesso del piano di esecuzione di Query Mars. Questo è lo sniffing dei parametri perché il piano di esecuzione memorizzato nella cache viene compilato per il piano di esecuzione di Query Mars. Per questo motivo, Query Venus utilizza lo stesso piano di esecuzione.
Ora disabiliteremo lo sniffing dei parametri ed eseguiremo le stesse query.
ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING =OFF; DBCC FREEPROCCACHE --Query Mars EXEC Get_OrderID_OrderQty @ProductID=870 --Query Venus EXEC Get_OrderID_OrderQty @ProductID=897
Esaminiamo:
L'ottimizzatore di query di SQL Server ha generato il piano di esecuzione ottimale per Query Venus e Query Mars. Questo approccio fornisce le prestazioni ottimali alla query.
Ci sono alcune opzioni per evitare questo problema:
- OPZIONE(RICIMPILA)
- OPZIONE (OTTIMIZZA PER(@VARIABLE=SCONOSCIUTO))
Correzione automatica del piano
SQL Server 2017 include una nuova funzionalità denominata Correzione automatica del piano. Quando eseguiamo una query, Query Optimizer crea un piano di esecuzione. Per alcuni motivi, Query Optimizer sceglie piani di esecuzione errati. Alcuni dei motivi sono i seguenti:
- Una query che non soddisfa i criteri di prestazione
- Statistiche non aggiornate
- Indici non idonei
Quando Query Optimizer di SQL Server decide di modificare il piano di esecuzione e questo piano di esecuzione danneggia le prestazioni, le prestazioni della query vengono chiamate regressione del piano. Una nuova funzionalità viene fornita con SQL Server 2016. Questo strumento aiuta a monitorare e risolvere i problemi delle prestazioni delle query e allo stesso tempo archivia le metriche delle prestazioni e i contatori dell'esecuzione della query.
Possiamo abilitare queste opzioni nelle proprietà del database.
Ora faremo una demo di questa funzione. Prima di tutto, svuota la cache delle procedure e crea una stored procedure.
/**************************************** Don t use this script in production servers *****************************************/ USE WideWorldImporters ALTER DATABASE WideWorldImporters SET QUERY_STORE = ON; ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR ALL DBCC FREEPROCCACHE --This command will clear all procedure cache in SQL Server. Dont try in production envoierment-- ALTER DATABASE WideWorldImporters SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF); DROP PROCEDURE IF EXISTS Test_CoddingSight2 GO CREATE PROC Test_CoddingSight2 @Id AS INT AS select sum([UnitPrice]*[Quantity]) from Sales.OrderLines O INNER JOIN sales.Orders o1 ON o1.OrderID = o.OrderID where o.PackageTypeID = @Id
A questo punto, eseguiremo questa procedura con parametri diversi e troveremo la differenza di tempo di esecuzione.
--Query Alpha DBCC FREEPROCCACHE EXEC Test_CoddingSight2 7 GO 80 DBCC FREEPROCCACHE EXEC Test_CoddingSight2 -1 --Query Beta EXEC Test_CoddingSight2 7 GO 80
Come puoi vedere, la prima query è stata completata in 12 sec, mentre la seconda è stata eseguita in 33 sec. Il motivo di questa notevole differenza è che Query Optimizer sceglie un piano di esecuzione non adatto per Query Beta.
Confrontiamo i piani di esecuzione di Query Alpha e Query Beta.
Piano di esecuzione di Query Alpha
Piano di esecuzione di Query Beta
Nelle immagini sopra, Query Optimizer crea piani di esecuzione diversi per la stessa query. Quando esaminiamo le query che consumano risorse principali , possiamo vedere che Query Beta consuma più risorse di Query Alpha.
La query seguente restituirà informazioni dettagliate sui consigli di ottimizzazione.
SELECT name, reason, score, JSON_VALUE(details, '$.implementationDetails.script') as script, details.* FROM sys.dm_db_tuning_recommendations CROSS APPLY OPENJSON(details, '$.planForceDetails') WITH ( query_id int '$.queryId', regressed_plan_id int '$.regressedPlanId', last_good_plan_id int '$.recommendedPlanId') as details WHERE JSON_VALUE(state, '$.currentValue') = 'Active'
La colonna del motivo mostra perché dobbiamo applicare questo consiglio.
Ora, eseguiremo nuovamente Query Alpha e Query Beta con la correzione automatica del piano abilitata.
/**************************************** Don't use this script in production servers *****************************************/ ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR ALL DBCC FREEPROCCACHE /**************************************** Enable Automatic Plan Correction *****************************************/ ALTER DATABASE WideWorldImporters SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = ON); --Query Alpha DBCC FREEPROCCACHE EXEC Test_CoddingSight2 7 GO 80 DBCC FREEPROCCACHE EXEC Test_CoddingSight2 -1 --Query Beta EXEC Test_CoddingSight2 7 GO 80
Dopo questa demo, il piano di esecuzione di Query Alpha viene applicato a Query Beta. Inoltre, i tempi di esecuzione di Query Alpha e Query Beta sono vicini l'uno all'altro. La query seguente restituirà lo stato di correzione automatica del piano.
SELECT name, reason, score,JSON_VALUE(state, '$.currentValue') as status, JSON_VALUE(details, '$.implementationDetails.script') as script, details.* FROM sys.dm_db_tuning_recommendations CROSS APPLY OPENJSON(details, '$.planForceDetails') WITH ( query_id int '$.queryId', regressed_plan_id int '$.regressedPlanId', last_good_plan_id int '$.recommendedPlanId') as details WHERE JSON_VALUE(state, '$.currentValue') = 'Verifying'
Inoltre, possiamo trovare alcune informazioni grafiche in Query con piani forzati . Questo grafico definisce i piani di query forzati e la query.
Riferimenti
Correzione automatica del piano in SQL Server 2017
Stima della cardinalità