Они на самом деле эквивалентны, но они являются независимыми типами, а не технически синонимами, такими как ROWVERSION
и TIMESTAMP
- хотя их, возможно, упоминали как синонимы в документации когда-то . Это немного другое значение синонима (например, они неразличимы, кроме имени, ни один не является псевдонимом для другого). Иронично, правда?
Что я интерпретирую из формулировки в MSDN на самом деле:
Эти типы идентичны, они просто имеют разные имена.
Кроме type_id
значений, все здесь идентично:
SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');
Я абсолютно не знаю никаких поведенческих различий между ними, и, возвращаясь к SQL Server 6.5, всегда рассматривал их как взаимозаменяемые на 100%.
для десятичной (18,2) и числовой (18,2)? Присвоение одного другому технически является «преобразованием»?
Только если вы делаете это явно. Вы можете легко это доказать, создав таблицу, а затем проверив план запроса на наличие запросов, которые выполняют явные или - вы можете ожидать - неявные преобразования. Вот простая таблица:
CREATE TABLE [dbo].[NumDec]
(
[num] [numeric](18, 0) NULL,
[dec] [decimal](18, 0) NULL
);
Теперь выполните эти запросы и запишите план:
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
Как показано в SQL Sentry Plan Explorer *, план не очень интересен:
Но вкладка «Выражения» точно такая:
Как я прокомментировал выше, у нас есть явные преобразования там, где мы их просили, но нет явных преобразований там, где мы могли бы их ожидать. Кажется, оптимизатор также рассматривает их как взаимозаменяемые.
Попробуйте этот тест тоже (данные и индексы).
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]);
Теперь запустите этот запрос:
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;
План не имеет преобразований (фактически вкладка «Выражения» пуста):
Даже это не приводит к неожиданным преобразованиям. Конечно, вы видите это в RHS в предикате, но ни в коем случае не нужно было выполнять какое-либо преобразование данных столбца, чтобы облегчить поиск (тем более, принудительное сканирование).
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);
Лично я предпочитаю использовать этот термин DECIMAL
только потому, что он гораздо более точный и описательный. BIT
тоже "числовой".
* Disclaimer: I work for SQL Sentry.