一尘不染

NUMERIC 和 DECIMAL 之间有什么区别吗?

sql-server

我知道 SQL Server 中的 NUMERIC 和 DECIMAL 数据类型的工作方式相同:创建它们的语法相同,可以存储在其中的值范围相同,等等。

但是,MSDN 文档将两者之间的关系描述为:

numeric 在功能上等同于十进制。

通常,当我看到限定词“功能等效”时,这意味着这两个东西并不完全相同,而是它们是两种不同的类型,从外面无法区分

这个暗示是真的吗?NUMERIC 和 DECIMAL 之间是否存在恰好对外部观察者表现相同的差异?还是它们实际上是等价的,例如,NUMERIC 是否只是 DECIMAL 的旧同义词?


阅读 248

收藏
2022-11-03

共1个答案

一尘不染

它们实际上是等价的,但它们是独立的类型,而不是技术上的同义词,例如ROWVERSIONand TIMESTAMP- 尽管它们可能曾经在文档中被称为同义词。这是同义词的稍微不同的含义(例如,除了名称之外,它们无法区分,没有一个是另一个的别名)。很讽刺,对吧?

我从 MSDN 中的措辞解释的实际上是:

这些类型是相同的,只是名称不同。

除了type_id值之外,这里的一切都是相同的:

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

我完全不知道两者之间的任何行为差异,并且回到 SQL Server 6.5,始终将它们视为 100% 可互换。

对于 DECIMAL(18,2) 和 NUMERIC(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.
2022-11-03