C'è qualche differenza tra NUMERIC e DECIMAL?


47

So che i tipi di dati NUMERIC e DECIMAL in SQL Server funzionano allo stesso modo: la sintassi per crearli è la stessa, gli intervalli di valori che è possibile memorizzare in essi sono gli stessi, ecc.

Tuttavia, la documentazione MSDN descrive la relazione tra i due in questo modo:

numerico è funzionalmente equivalente al decimale.

Normalmente, quando vedo il qualificatore " funzionalmente equivalente", significa che le due cose non sono esattamente le stesse, ma che sono due tipi diversi che sono indistinguibili dall'esterno .

Questa implicazione è vera? Ci sono differenze tra NUMERIC e DECIMAL che si comportano allo stesso modo con un osservatore esterno? O sono effettivamente equivalenti, ad esempio NUMERIC è solo un sinonimo legacy di DECIMAL?


1
Potresti trovare differenze nel supporto al di fuori di SQL Server, ad esempio sono stato appena informato di questa strana differenza in SSIS .
Aaron Bertrand

Risposte:


56

In realtà sono equivalenti, ma sono tipi indipendenti e non tecnicamente sinonimi, come ROWVERSIONe TIMESTAMP- sebbene possano essere stati indicati come sinonimi nella documentazione in una sola volta . Questo è un significato leggermente diverso di sinonimo (ad esempio sono indistinguibili se non nel nome, non uno è un alias per l'altro). Ironico, vero?

Quello che interpreto dal testo in MSDN è in realtà:

Questi tipi sono identici, hanno solo nomi diversi.

A parte i type_idvalori, tutto qui è identico:

SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');

Non ho assolutamente alcuna conoscenza di eventuali differenze comportamentali tra i due e, tornando a SQL Server 6.5, li ho sempre trattati come intercambiabili al 100%.

per DECIMAL (18,2) e NUMERIC (18,2)? Assegnare l'una all'altra è tecnicamente una "conversione"?

Solo se lo fai esplicitamente. Puoi dimostrarlo facilmente creando una tabella e quindi ispezionando il piano di query per query che eseguono conversioni esplicite o - potresti aspettarti - implicite. Ecco una semplice tabella:

CREATE TABLE [dbo].[NumDec]
(
    [num] [numeric](18, 0) NULL,
    [dec] [decimal](18, 0) NULL
);

Ora esegui queste query e acquisisci il piano:

DECLARE @num NUMERIC(18,0);
DECLARE @dec DECIMAL(18,0);

SELECT 
  CONVERT(DECIMAL(18,0), [num]), -- conversion
  CONVERT(NUMERIC(18,0), [dec])  -- conversion
FROM dbo.NumDec
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [num] = @dec  -- no conversion
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [dec] = @num; -- no conversion

Come mostrato in SQL Sentry Plan Explorer *, il piano non è davvero interessante:

inserisci qui la descrizione dell'immagine

Ma la scheda Espressioni è sicuramente:

inserisci qui la descrizione dell'immagine

Come ho commentato sopra, abbiamo conversioni esplicite dove le abbiamo richieste, ma nessuna conversione esplicita dove ci saremmo potuti aspettare. Sembra che l'ottimizzatore li stia trattando anche come intercambiabili.

Vai avanti e prova anche questo test (dati e indici).

CREATE TABLE [dbo].[NumDec2]
(
    [num] [numeric](18, 2) NULL,
    [dec] [decimal](18, 2) NULL
);

INSERT dbo.NumDec2([num],[dec])
SELECT [object_id] + 0.12, [object_id] + 0.12
  FROM sys.all_columns;

CREATE INDEX [ix_num] ON dbo.NumDec2([num]);
CREATE INDEX [ix_dec] ON dbo.NumDec2([dec]);

Ora esegui questa query:

DECLARE @num NUMERIC(18,2) = -1291334356.88,
        @dec NUMERIC(18,2) = -1291334356.88;

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = @num
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = @dec;

Il piano non ha conversioni (in effetti la scheda Espressioni è vuota):

inserisci qui la descrizione dell'immagine

Anche questi non portano a conversioni inaspettate. Ovviamente lo si vede sull'RHS nel predicato, ma in nessun caso è stata necessaria alcuna conversione rispetto ai dati della colonna per facilitare la ricerca (tanto meno forzare una scansione).

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @dec);

Personalmente, preferisco usare il termine DECIMALsolo perché è molto più preciso e descrittivo. BITè anche "numerico".

* Disclaimer: I work for SQL Sentry.

So che SQL tratta, ad esempio DECIMAL (18,2) e DECIMAL (18,0) come "tipi diversi"; significa lo stesso per DECIMAL (18,2) e NUMERIC (18,2)? Assegnare l'una all'altra è tecnicamente una "conversione"?
KutuluMike,

@MichaelEdenfield Ho aggiornato la mia risposta per la tua nuova domanda.
Aaron Bertrand

1
So che questa è una vecchia risposta, ma ho appena trovato un caso in cui pensare che numerico e decimale siano sinonimi ha causato un errore in SQL Server. Ho pensato di lasciare un commento qui nel caso qualcun altro potesse trarne beneficio.
Zohar Peled,

@AaronBertrand Ho votato a favore della tua risposta perché è utile. Entrambi i tipi sembrano identici, quindi se è così, perché sono chiamati in modo diverso? c'è qualche motivo storico ?
Ivanzinho,

@Ivanzinho Non sono sicuro che la tua domanda sia retorica, ci sono un sacco di teorie (sia in questa pagina che nella risposta che hai collegato), ma se vuoi una risposta definitiva, probabilmente non avrai fortuna. Dovresti rintracciare gli ingegneri originali che per primi hanno implementato entrambi i tipi in SQL Server e fare affidamento sulla loro memoria sia dell'implementazione che della loro interpretazione dello standard in quel momento.
Aaron Bertrand

15

Sono identici nella pratica, tuttavia (dallo standard SQL 2003):

21) NUMERIC specifica il tipo di dati numerico esatto, con la precisione decimale e la scala specificate da precisione scale.

22) DECIMAL specifica il tipo esatto di dati numerici, con la scala decimale specificata dalla scalee la precisione decimale definita dall'implementazione uguale o maggiore del valore del valore specificato precision.


5
La domanda fondamentale allora (e credo che la risposta sia no), SQL Server ha implementato la precisione di DECIMAL in modo diverso rispetto a NUMERIC. Ciò che la norma dice potrebbe essere fatto è molto meno rilevante di ciò che è stato effettivamente fatto.
Aaron Bertrand

5
Grazie. Questa è un'ottima risposta alla domanda di follow-up sul perché ci sono due tipi con nomi diversi ma con comportamento identico.
Gabe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.