Udostępnij za pośrednictwem


E i DECIMAL con scala a 0 ?

Inizio con una domanda, non me ne vogliate.

Chi di voi ha mai visto / creato colonne di tipo DECIMAL con scala uguale a 0?

 

Intendo dire qualcosa come:

 CREATE TABLE myTable
(
    ...
    myColumn DECIMAL( 3 , 0 ) , 
    ...
);

 

Chi di voi si è mai chiesto che senso ha creare colonne DECIMAL con scala uguale a 0?

Il senso è, naturalmente, quello di poter gestire numeri interi. Ok.

 

Avevo già toccato l’argomento in un altro post, in questo vorrei tornare sull’argomento con un ragionamento più generale.

 

Avendo in mente lo storage necessario alla memorizzazione di dati DECIMAL a seconda della precisione definita, l’idea è quella di realizzare uno script che possa analizzare la dimensione (precisione) definita con scala = 0 per verificare la possibilità di modificarne il tipo (in un intero “naturale” come sono i TINYINT, SMALLINT, INT, BIGINT) in ottica di risparmio bytes.

 

Intendo dire, che senso ha utilizzare un DECIMAL(9,0) quando sarebbe sufficiente utilizzare un INT (e quindi utilizzare 4 bytes rispetto ai 5 del DECIMAL)?

 DECLARE @decimal decimal( 9 , 0 ) = 999999999;
DECLARE @int int = @decimal;
SELECT
       @int [Value], 
       DATALENGTH( @int ) [INT Bytes], 
       DATALENGTH( @decimal ) [DECIMAL Bytes];

image

 

In sostanza, fino ad una precisione di 18 cifre potrei modificare il tipo per ottenerne un beneficio.

Questo perché, naturalmente, potrei utilizzare un BIGINT per memorizzare un numero (positivo o negativo) composto da 18 cifre uguali a 9 (il massimo valore gestibile con un DECIMAL(18,0)).

 

Provando a schematizzare:

  • decimal(1), (2) : potrei usare TINYINT - con decimal 5 bytes, potrei risparmiare 4 bytes
  • decimal(3) : potrei usare SMALLINT - con decimal 5 bytes, risparmio 3 bytes
  • decimal(4), (5), (6), (7), (8), (9) : potrei usare INT - con decimal 5 bytes, risparmio 1 byte
  • decimal(10), (11), (12), (13), (14), (15), (16), (17), (18) : potrei usare BIGINT - con decimal 9 bytes, risparmio 1 byte

 

Di seguito il risultato di quella che potrebbe essere l’analisi sulle tabelle di un nostro database:

image

Questo lo script:

 SELECT 
    C.TABLE_SCHEMA, C.TABLE_NAME, 
    C.COLUMN_NAME, 
    'DECIMAL('+ CAST(C.NUMERIC_PRECISION as varchar(2)) + ',0)' as [Currently Data Type],
    case 
       when NUMERIC_PRECISION <= 9 then 5 
       when NUMERIC_PRECISION <= 19 then 9
       when NUMERIC_PRECISION <= 28 then 13
       when NUMERIC_PRECISION <= 38 then 17
    end as [Used Bytes],
    case 
       when NUMERIC_PRECISION between 1 and 2 then 'TINYINT'
       when NUMERIC_PRECISION = 3 then 'SMALLINT'
       when NUMERIC_PRECISION between 4 and 9 then 'INT'
       when NUMERIC_PRECISION between 10 and 18 then 'BIGINT'
       else '-'
    end as [Proposed Data Type],
    case 
       when NUMERIC_PRECISION <= 2 then 4
       when NUMERIC_PRECISION = 3 then 3
       when NUMERIC_PRECISION <= 9 then 1
       when NUMERIC_PRECISION <= 18 then 1
       else 0
    end as [Saved Bytes per Column]
FROM INFORMATION_SCHEMA.COLUMNS  C
JOIN INFORMATION_SCHEMA.tables T ON
    C.TABLE_SCHEMA = T.TABLE_SCHEMA and
    C.TABLE_NAME = T.TABLE_NAME 
WHERE
    T.TABLE_TYPE = 'BASE TABLE' AND 
    C.DATA_TYPE = 'decimal' AND 
    C.NUMERIC_SCALE = 0
ORDER BY
    T.TABLE_SCHEMA, T.TABLE_NAME, C.COLUMN_NAME
GO

 

Terminando i ragionamenti, credo che l’uso di un DECIMAL con scala = 0 sia utile soltanto nel momento in cui ho una di queste due necessità:

  • memorizzare valori maggiori di 9.223.372.036.854.775.807
  • memorizzare valori minori di -9.223.372.036.854.775.808

In sostanza gestire interi che non è possibile, per la loro dimensione, memorizzare con il tipo BIGINT.

 

Nota.

Visto che abbiamo parlato di DECIMAL, ricordo che il formato di archiviazione vardecimal è deprecato:

Con la compressione dei dati di SQL Server 2012 vengono compressi sia i valori decimali sia gli altri tipi di dati. È consigliabile utilizzare la compressione dei dati anziché il formato di archiviazione vardecimal.

Per il dettaglio delle funzionalità dichiarate come deprecate con SQL Server 2012, si veda qui.

Comments

  • Anonymous
    November 13, 2013
    Negli scorsi 9 mesi ho lavorato su una applicaizone bancario con 150.000 clienti. Tutte dico tutte le tabella avevano PK decimal(9,0) e tutte dico tutte le date erano varchar(9)... non vado oltre per adesso :-)

  • Anonymous
    November 13, 2013
    No, dai, vai oltre... sarebbe una bella lezione ;-)