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

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

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!!

Chi è Luca Bruni

Luca Bruni ottiene la Laurea Magistrale in Ingegneria Informatica presso il Politecnico di Milano (sede di Como) nel 2006. Ha lavorato in diverse aziende coprendo vari ruoli: Software Developer, Consultant, Project Manager. Dal 2010 lavora in qualità di Software & Data Architect presso una nota software house svizzera. Lavora con SQL Server dalla versione 2000 e da Dicembre 2016 è Contributor UGISS.

Leggi Anche

SQL Server Management Studio 17.3

E’ stato rilasciata qualche giorno fa la nuova versione di SQL Server Management Studio (17.3) Oltre …