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

Kut*_*ike 48 sql-server

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

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

数字在功能上等同于十进制。

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

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

Aar*_*and 58

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

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

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

除了type_id值之外,这里的所有内容都是相同的:

SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');
Run Code Online (Sandbox Code Playgroud)

我完全不知道两者之间的任何行为差异,回到 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
);
Run Code Online (Sandbox Code Playgroud)

现在运行这些查询并捕获计划:

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
Run Code Online (Sandbox Code Playgroud)

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]);
Run Code Online (Sandbox Code Playgroud)

现在运行这个查询:

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;
Run Code Online (Sandbox Code Playgroud)

计划没有转换(实际上表达式选项卡是空的):

在此处输入图片说明

即使这些也不会导致任何意外的转换。当然,您可以在谓词的 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);
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我更喜欢使用这个术语DECIMAL,因为它更准确、更具描述性。BIT也是“数字”。

* Disclaimer: I work for SQL Sentry.
Run Code Online (Sandbox Code Playgroud)


Nei*_*gan 17

然而,它们在实践中是相同的(来自 SQL 2003 标准):

21) NUMERIC 指定数据类型精确数字,小数精度和小数位数由precision和指定 scale

22) DECIMAL 指定数据类型精确数字,具有由 指定的十进制小数位scale实现定义的十进制精度等于或大于指定的值precision

  • 那么基本问题(我相信答案是否定的),SQL Server 实现 DECIMAL 的精度是否与 NUMERIC 的精度不同。标准所说的*可以*做的事情远没有实际做的那么重要。 (5认同)
  • 谢谢。这是对为什么有两种名称不同但行为相同的后续问题的一个很好的回答。 (5认同)