Archivi categoria: Articoli

PowerShell Core 6.0: una nuova era ha inizio

Facebooktwittergoogle_plusredditlinkedin

Da qualche giorno è disponibile una nuova versione di Windows PowerShell, giunta ormai alla sesta versione. La grande novità risiede nell’introduzione della versione Core, che ha l’obiettivo di portare l’utilizzo della shell Microsoft su tutti […]

Conversioni implicite: La plan cache ci svela quante sono e dove avvengono!

Facebooktwittergoogle_plusredditlinkedin

Nell’articolo Conversioni implicite: cosa sono e che impatto hanno sulle nostre query, Luca Bruni (@mrg3d) ci ha parlato delle conversioni implicite che avvengono, a nostra insaputa, all’interno dell’Engine di SQL Server. Tali conversioni, possono costringere il Query Optimizer ad accedere alle tabelle con operazioni di scansione (Table Scan, Index Scan) in alternativa alle più efficienti operazioni di Seek (Index Seek), e quando una parte significativa del carico di lavoro è interessata da conversioni implicite, le performance degradano visibilmente!

Una conversione implicita tra due tipi di dato differenti avviene sempre dal tipo di dato meno preciso al tipo di dato più preciso. Per ovvie ragioni, SQL Server non può perdere precisione nei dati a causa di una conversione implicita, parlando quindi di tipi di dato testo, una conversione implicita potrà avvenire, ad esempio, dal tipo VARCHAR (meno preciso) al tipo NVARCHAR (più preciso), mai nella direzione opposta.

Probabilmente vi starete chiedendo se il vostro carico di lavoro è affetto da conversioni implicite e in che percentuale.

Le conversioni implicite, all’interno del piano di esecuzione, vengono segnalate con un warning. Il Query Optimizer può segnalare i seguenti tipi di warning:

  • No statistics (ColumnsWithNoStatistics)
  • No join predicate (NoJoinPredicate)
  • Implicit conversions (PlanAffectingConvert)
  • Sort on tempdb (SpillToTempDb)
  • No matched indexes (UnmatchedIndexes)
  • Wait (WaitWarningType)

..tra cui troviamo l’Implicit Conversions Warning (PlanAffectingConvert) di cui parleremo in questo articolo.

Il warning PlanAffectingConvert viene segnalato proprio in presenza di conversioni implicite, quando viene utilizzata la funzione CONVERT_IMPLICIT. È quindi possibile fare indagini sulla presenza di conversioni implicite nel carico di lavoro analizzando la plan cache, ovvero l’area di memoria utilizzata da SQL Server per memorizzare i piani di esecuzione delle query.

Utilizzando la metodologia “top-down” per analizzare il problema, il primo dato che vorremmo avere è la percentuale dei piani di esecuzione in cache affetti da conversioni implicite. Per ottenerlo dovremo contare i piani di esecuzione in cache, e di questi, quelli affetti da conversioni implicite… la seguente CTE estrae le informazioni che cerchiamo: il numero dei piani di esecuzione in cache, il numero dei piani di esecuzione in cui viene utilizzata la funzione CONVERT_IMPLICIT ed il calcolo della percentuale.

WITH XMLNAMESPACES
(
 DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan'
),
Cached_Plans AS
(
 SELECT
 COUNT(cp.plan_handle) AS Total_Plan_Cached
 FROM
 sys.dm_exec_cached_plans AS cp
),
Cached_Plans_with_Convert AS
(
 SELECT
 COUNT(cp.plan_handle) AS Total_Plan_Cached_with_Convert
 FROM
 sys.dm_exec_cached_plans AS cp
 CROSS APPLY
 sys.dm_exec_query_plan(cp.plan_handle) AS qp
 CROSS APPLY
 sys.dm_exec_sql_text(cp.plan_handle) AS qt
 WHERE
 (qp.query_plan.exist('//Warnings') = 1)
 AND CAST(qp.query_plan.query('//Warnings') AS VARCHAR(MAX)) LIKE '%CONVERT_IMPLICIT%'
)
SELECT
 Total_Plan_Cached
 ,Total_Plan_Cached_with_Convert = (SELECT Total_Plan_Cached_with_Convert FROM Cached_Plans_with_Convert)
 ,CAST(CAST((SELECT Total_Plan_Cached_with_Convert FROM Cached_Plans_with_Convert) AS DECIMAL(10,3)) / 
 CAST(Total_Plan_Cached AS DECIMAL(10,3)) AS DECIMAL(6,3)) * 100 [% Plan_Cached_with_Convert]
FROM
 Cached_Plans;

L’output di esempio è illustrato nelle figura seguente, dove circa il 4% del carico di lavoro è affetto da conversioni implicite.

Qualora venisse rilevato un numero considerevole di piani di esecuzione affetti da conversioni implicite, la seguente CTE ci potrà aiutare nell’identificazione delle query specifiche in cui avvengono le conversioni implicite, tra le colonne estratte vi è il testo della query, il piano di esecuzione completo e la porzione relativa ai warning di tipo PlanAffectingConvert in cui è stata utilizzata la funzione CONVERT_IMPLICIT.

WITH XMLNAMESPACES
(
 DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan'
),
PlanAffectingConvert AS
(
 SELECT
 query_text = qt.text
 ,cp.objtype
 ,cp.refcounts
 ,cp.usecounts
 ,Plan_Warnings = qp.query_plan.query('//Warnings')
 ,qp.query_plan
 FROM
 sys.dm_exec_cached_plans AS cp
 CROSS APPLY
 sys.dm_exec_query_plan(cp.plan_handle) AS qp
 CROSS APPLY
 sys.dm_exec_sql_text(cp.plan_handle) AS qt
 WHERE
 (qp.query_plan.exist('//Warnings') = 1)
)
SELECT
 *
FROM
 PlanAffectingConvert
WHERE
 CAST(Plan_Warnings AS VARCHAR(MAX)) LIKE '%CONVERT_IMPLICIT%';

Concludendo, se avete il dubbio che il vostro carico di lavoro sia affetto da conversioni implicite, un buon punto di partenza è l’utilizzo delle query descritte in questo articolo… se pensate di non avere conversioni implicite nelle vostre query, fate lo stesso un controllo… non costa nulla!

Buon divertimento!

Veeam Backup & Replication 9.5: Error Code 32768

Facebooktwittergoogle_plusredditlinkedin

Uno dei problemi più fastidiosi con i software di backup è quando smettono di fare correttamente il loro lavoro. Nel caso di Veeam Backup & Replication 9.5 può capitare che alcune macchine virtuali non vengano più salvate e che l’errore mostrato dal log sia il seguente:

Failed to create VM recovery checkpoint (mode: Veeam application-aware processing) Details: Job failed (”). Error code: ‘32768’. Failed to create VM recovery snapshot, VM ID ’62bfb4be-a38a-4c27-a360-ee5f87ccbb93′. Retrying snapshot creation attempt (Failed to create production checkpoint.) Task has been rescheduled Queued for processing at 10/18/2017 10:40:08 PM Unable to allocate processing resources. Error: Job failed (”). Error code: ‘32768’. Failed to create VM recovery snapshot, VM ID ’62bfb4be-a38a-4c27-a360-ee5f87ccbb93′.

Le soluzioni al problema possono essere diverse ma la causa invece è solitamente una ed è legata al VSS Writer. Con SQL Server potrebbe essere necessario reinstallare i componenti, mentre per quanto riguarda i Domain Controller la cosa può essere risolta facendo un semplice riavvio.

Non è ancora chiaro il perchè di questo comportamento ma forse con la prossima Update Rollup 3 il problema potrebbe essere risolto.

Conversioni implicite: cosa sono e che impatto hanno sulle nostre query

Facebooktwittergoogle_plusredditlinkedin

Come credo alla maggior parte di voi, spesso, anche a me capita di dover mantenere codice scritto da qualcun altro. Uno degli aspetti che (ri)trovo con una certa frequenza è che, spesso, non prestiamo attenzione a come scriviamo le nostre query, sottovalutando l’impatto che queste possono avere sul nostro sistema.

Proprio recentemente mi sono imbattuto in una serie di batch (dalle semplici query a complesse procedure) dove non si era prestata la dovuta attenzione all’utilizzo dei tipi dato (ad esempio nella definizione di variabili e costanti, ma anche nelle colonne delle stesse tabelle), andando di fatto a creare qualche inconveniente, oltre che di mera natura estetica (e quindi di qualità del codice), anche (e soprattutto) di natura prestazionale. Buona parte di questi problemi era dovuta all’utilizzo frequente delle funzioni di conversione CAST e CONVERT (dovuti a probabili errori di modellazione delle tabelle come ad esempio stessa colonna in due tabelle differenti ma con differente tipo dato), ma la parte più critica e rilevante era dovuta  alla presenza di una miriade di conversioni implicite.

Affrontiamo la questione per gradi e facciamo un piccolo passo indietro, partendo dalle basi, cercando di capire cosa siano e che impatto possano avere nei nostri sistemi.

Per “conversione” si intende quell’ “operazione con cui si traduce un valore espresso in una determinata unità di misura in un altro valore, espresso in un’altra unità di misura” (Wikipedia).

Riadattando opportunamente la definizione, possiamo dire che all’interno del nostro contesto una conversione è quell’operazione tramite cui è possibile tradurre un valore espresso in un determinato tipo dato in un valore espresso in un altro tipo dato.

Nel mettere in relazione dunque due tipi dato qualsiasi si possono sostanzialmente verificare tre casi:

  • La conversione non è consentita:
    • non è ad esempio possibile convertire un tipo dato BIT in un tipo dato DATE
    • l’esecuzione forzata di una tale conversione produce un errore (“Explicit conversion from data type bit to date is not allowed.“)
  • La conversione è consentita e deve avvenire esplicitamente
    • ovvero è possibile solo tramite l’utilizzo delle funzioni CAST o CONVERT (come ad es. tra CHAR e BINARY)
  • La conversione è consentita ed avvenire in modo implicito
    • ovvero avviene in maniera automatica senza bisogno di utilizzare le funzioni CAST o CONVERT  (come ad es. tra CHAR e NCHAR)
    • l’automazione è gestita direttamente dal Query Processor (QP) ed avviene tramite l’ausilio della funzione riservata CONVERT_IMPLICIT

Combinando tutte le possibili coppie di tipo dato otteniamo una matrice dove possiamo leggere se e come la conversione può avvenire. Questa matrice è visibile sulla documentazione online nella pagina di documentazione dei metodi CAST e CONVERT.

NB: Si noti che la matrice contiene anche qualche caso particolare, però non rilevante ai fini della nostra analisi e comunque riconducibile ad una delle tre casistiche sopra riportate.

Chi di voi si è già preso la briga di “sbirciare” la matrice delle conversioni avrà già notato a colpo d’occhio quanto siano numerose le casistiche in cui una conversione implicita si possa verificare. Ecco dunque che diventa essenziale conoscere gli scenari di errore più comuni in modo da poterli evitare o comunque affrontare in modo sereno e consapevole: vediamo qualche esempio pratico tramite l’ausilio del database AdventureWorks.

Proviamo ad eseguire la seguente query:

SELECT BusinessEntityID, JobTitle, HireDate
FROM HumanResources.Employee
WHERE NationalIDNumber = '112457891'

Questo il piano di esecuzione:

Ad una prima occhiata non sembrerebbe presentare nulla di particolare. Ma in realtà esplorando i dettagli dell’operazione “Index Seek” notiamo che il QP ha applicato la funzione CONVERT_IMPLICIT  alla nostra costante riscrivendo di fatto il Seek Predicate. Ciò è dovuto all’utilizzo di un qualificatore di stringa non coerente con il tipo dato della colonna “NationalIDNumber” (NVARCHAR(15)). In particolare abbiamo utilizzato una stringa delimitata da apici singoli (‘112457891′) la quale viene identificata dal sistema come una stringa non-Unicode, mentre avremmo dovuto utilizzare una stringa delimitata da apici preceduti da una lettera N (maiuscola) (N’112457891’) la quale indica invece una stringa di caratteri Unicode e quindi in accordo con il tipo dato della colonna.

Correggendo dunque la query nel seguente modo

SELECT BusinessEntityID, JobTitle, HireDate
FROM HumanResources.Employee
WHERE NationalIDNumber = N'112457891'

possiamo notare come il “Seek Predicate” sia molto più semplice e non faccia più utilizzo della funzione di conversione implicita.

Tuttavia, se concludessimo qui la nostra analisi, tralasceremmo l’aspetto rilevante della questione, ovvero la valutazione dell’impatto che una conversione implicita può avere sulle scelte operate dal QP. A tal proposito vediamo cosa succede se, ad esempio, utilizziamo una costante numerica al posto di una costante stringa all’interno della nostra query:

SELECT BusinessEntityID, JobTitle, HireDate
FROM HumanResources.Employee
WHERE NationalIDNumber = 112457891

Osserviamo il piano d’esecuzione:

Ullalla!!! La conversione implicita, questa volta, ha prodotto un cambiamento decisamente impattante e negativo: l’operazione che prima era una “Index Seek” è ora diventata una “Index Scan”!

Questo degrado è giustificato dal fatto che l’utilizzo di una funzione (sia esso implicito o esplicito) all’interno di un predicato di filtro compromette la cossiddetta SARGability dell’intera clausola e di fatto vanifica l’utilizzo di ogni eventuale indice disponibile sulla nostra tabella, obbligandoci ad effetuarne una intera scansione.

Possiamo dunque concludere che quando nei piani di esecuzione delle nostre query compaiono delle conversioni implicite, queste sono sovente un’indicazione di scarse performance nonchè dei possibili indicatori di errori di design dei nostri schema. Riallacciandomi all’introduzione, aggiungo che è dunque bene prestare molta attenzione al modo in cui scriviamo le nostre query perchè (talvolta inconsapevolmente) potremmo creare delle situazioni molto spiacevoli e, magari, di non facile identificazione!

Ultima nota… alcuni tipi dato (ad es. quelli testuali) sono strutturati secondo particolari bit-pattern (la COLLATION) e che i passaggi tra differenti Collation comportano una conversione implicita!

Fate attenzione!!