In realtà sono equivalenti, ma sono tipi indipendenti e non tecnicamente sinonimi, come ROWVERSION
e 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_id
valori, 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:
Ma la scheda Espressioni è sicuramente:
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):
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 DECIMAL
solo perché è molto più preciso e descrittivo. BIT
è anche "numerico".
* Disclaimer: I work for SQL Sentry.