W rzeczywistości są one równoważne, ale są niezależnymi typami, a nie technicznie synonimami, takimi jak ROWVERSION
i TIMESTAMP
- chociaż mogły być jednocześnie określane w dokumentacji jako synonimy . Jest to nieco inne znaczenie synonimu (np. Są nierozróżnialne, z wyjątkiem nazwy, żaden nie jest pseudonimem dla drugiego). Ironiczne, prawda?
To, co interpretuję ze sformułowania w MSDN, to w rzeczywistości:
Te typy są identyczne, mają tylko różne nazwy.
Poza type_id
wartościami wszystko tutaj jest identyczne:
SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');
Nie mam absolutnie żadnej wiedzy na temat różnic w zachowaniu między nimi, a wracając do SQL Server 6.5, zawsze traktowałem je jako w 100% wymienne.
dla DECIMAL (18,2) i NUMERIC (18,2)? Przypisywanie sobie nawzajem jest technicznie „konwersją”?
Tylko jeśli zrobisz to wyraźnie. Możesz to łatwo udowodnić, tworząc tabelę, a następnie sprawdzając plan zapytań pod kątem zapytań, które wykonują jawne lub - można się spodziewać - niejawne konwersje. Oto prosty stół:
CREATE TABLE [dbo].[NumDec]
(
[num] [numeric](18, 0) NULL,
[dec] [decimal](18, 0) NULL
);
Teraz uruchom te zapytania i zrób plan:
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
Jak pokazano w SQL Sentry Plan Explorer *, plan nie jest tak naprawdę interesujący:
Ale zakładka Wyrażenia jest z pewnością:
Jak skomentowałem powyżej, mamy wyraźne konwersje tam, gdzie o nie poprosiliśmy, ale żadnych wyraźnych konwersji, w których moglibyśmy się ich spodziewać. Wydaje się, że optymalizator również traktuje je jako wymienne.
Śmiało i wypróbuj również ten test (dane i indeksy).
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]);
Teraz uruchom to zapytanie:
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;
Plan nie zawiera żadnych konwersji (w rzeczywistości karta Wyrażenia jest pusta):
Nawet te nie prowadzą do nieoczekiwanych konwersji. Oczywiście widzisz to na RHS w predykacie, ale w żadnym wypadku nie musiała wystąpić żadna konwersja w stosunku do danych kolumny, aby ułatwić wyszukiwanie (znacznie mniej wymuszając skanowanie).
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);
Osobiście wolę używać tego terminu DECIMAL
tylko dlatego, że jest on o wiele bardziej dokładny i opisowy. BIT
jest również „numeryczny”.
* Disclaimer: I work for SQL Sentry.