我很好奇货币数据类型和十进制(19,4)之类的数据类型之间是否有真正的区别(我相信这是货币内部使用的)。

我知道钱是特定于SQL Server的。我想知道是否有令人信服的理由来选择一个而不是另一个;大多数SQL Server样本(例如AdventureWorks数据库)使用金钱而不是小数来表示价格信息。

我是否应该继续使用货币数据类型,或者使用十进制是否有好处?金钱可以输入的字符更少,但这不是一个有效的理由:)


当前回答

作为对其他答案主旨的反驳。看金钱的诸多好处…数据类型!在SQLCAT的关系引擎指南中

我要具体指出以下几点

Working on customer implementations, we found some interesting performance numbers concerning the money data type. For example, when Analysis Services was set to the currency data type (from double) to match the SQL Server money data type, there was a 13% improvement in processing speed (rows/sec). To get faster performance within SQL Server Integration Services (SSIS) to load 1.18 TB in under thirty minutes, as noted in SSIS 2008 - world record ETL performance, it was observed that changing the four decimal(9,2) columns with a size of 5 bytes in the TPC-H LINEITEM table to money (8 bytes) improved bulk inserting speed by 20% ... The reason for the performance improvement is because of SQL Server’s Tabular Data Stream (TDS) protocol, which has the key design principle to transfer data in compact binary form and as close as possible to the internal storage format of SQL Server. Empirically, this was observed during the SSIS 2008 - world record ETL performance test using Kernrate; the protocol dropped significantly when the data type was switched to money from decimal. This makes the transfer of data as efficient as possible. A complex data type needs additional parsing and CPU cycles to handle than a fixed-width type.

所以这个问题的答案是“视情况而定”。对于某些算术操作,您需要更加小心,以保持精度,但您可能会发现,出于性能考虑,这样做是值得的。

其他回答

如果你不知道自己在做什么,一切都是危险的

即使是高精度的十进制类型也无法扭转局面:

declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000

1.000000 <-应该是0.6000000


货币类型是整数

smallmoney和decimal(10,4)的文本表示可能看起来很像,但这并不意味着它们可以互换。当您看到日期存储为varchar(10)时,您会感到畏缩吗?这是一样的。

在幕后,money/smallmoney只是一个bigint/int。money的文本表示中的小数点在视觉上是无用的,就像yyyy-mm-dd日期中的破折号。SQL实际上并没有在内部存储这些数据。

关于十进制和金钱,选择任何适合你需要的。货币类型的存在是因为将会计值存储为单位的1/ 10000000的整数倍数是非常常见的。此外,如果您正在处理实际的货币和计算,而不仅仅是简单的加减法,那么您不应该在数据库级别上这样做!在应用程序级别使用支持Banker's舍入的库进行计算(IEEE 754)

我喜欢钱!它比DECIMAL少一个字节,而且计算执行得更快,因为(实际上)加法和减法操作本质上是整数操作。@SQLMenace的例子——这对不了解情况的人是一个很大的警告——同样可以应用于整数,其结果将为零。但这并不是不使用整数的理由——在适当的地方。

所以,当你处理的是金钱,并根据它遵循的数学规则(与整数相同)使用金钱时,使用金钱是完全“安全”和适当的。

如果SQL Server将MONEY的除法和乘法转换为小数(或浮点数?)会更好吗?可能,但他们没有选择这样做;在除法时,他们也没有选择将整数提升为浮点数。

金钱没有精确度问题;小数在计算过程中使用更大的中间类型只是使用该类型的一个“特征”(我实际上不确定这个“特征”延伸了多远)。

要回答具体的问题,一个“令人信服的理由”?好吧,如果你想在SUM(x)中获得绝对最大性能,其中x可以是DECIMAL或MONEY,那么MONEY将具有优势。

另外,不要忘记它的小表兄弟smallmoney——只有4个字节,但它的最大值为214,748.3647——这对于钱来说非常小——因此通常不适合。

为了证明使用更大的中间类型的观点,如果你显式地将中间类型赋值给一个变量,DECIMAL也会遇到同样的问题:

declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)

select @a = 100, @b = 339, @c = 10000

set @d = @a/@b

set @d = @d*@c

select @d

产生2950.0000(好吧,至少是DECIMAL四舍五入,而不是MONEY截断——与整数相同。)

作为对其他答案主旨的反驳。看金钱的诸多好处…数据类型!在SQLCAT的关系引擎指南中

我要具体指出以下几点

Working on customer implementations, we found some interesting performance numbers concerning the money data type. For example, when Analysis Services was set to the currency data type (from double) to match the SQL Server money data type, there was a 13% improvement in processing speed (rows/sec). To get faster performance within SQL Server Integration Services (SSIS) to load 1.18 TB in under thirty minutes, as noted in SSIS 2008 - world record ETL performance, it was observed that changing the four decimal(9,2) columns with a size of 5 bytes in the TPC-H LINEITEM table to money (8 bytes) improved bulk inserting speed by 20% ... The reason for the performance improvement is because of SQL Server’s Tabular Data Stream (TDS) protocol, which has the key design principle to transfer data in compact binary form and as close as possible to the internal storage format of SQL Server. Empirically, this was observed during the SSIS 2008 - world record ETL performance test using Kernrate; the protocol dropped significantly when the data type was switched to money from decimal. This makes the transfer of data as efficient as possible. A complex data type needs additional parsing and CPU cycles to handle than a fixed-width type.

所以这个问题的答案是“视情况而定”。对于某些算术操作,您需要更加小心,以保持精度,但您可能会发现,出于性能考虑,这样做是值得的。

我们刚刚遇到了一个非常相似的问题,我现在非常+1,因为除了在顶级演示中,我从不使用Money。我们有多个表(实际上是一个销售凭证和一个销售发票),由于历史原因,每个表都包含一个或多个Money字段,我们需要按比例计算出总发票中有多少Tax与销售凭证上的每一行相关。我们的计算是

vat proportion = total invoice vat x (voucher line value / total invoice value)

这将导致现实世界中的货币/货币计算,从而导致在分割部分上的刻度错误,然后乘以一个不正确的增值税比例。当这些价值随后相加时,我们最终得到的是增值税比例的总和,加起来不等于发票总价值。如果括号中的任何一个值是小数(我将把其中一个转换为小数),vat比例将是正确的。

当括号不存在的时候,原来这是工作的,我猜是因为涉及到更大的值,它有效地模拟了一个更高的规模。我们添加括号是因为它先做乘法运算,这在一些罕见的情况下会破坏计算的精度,但这现在已经导致了这个更常见的错误。

我刚看到这个博客:SQL Server中的金钱vs.十进制。

这基本上是说金钱有一个精确的问题……

declare @m money
declare @d decimal(9,2)

set @m = 19.34
set @d = 19.34

select (@m/1000)*1000
select (@d/1000)*1000

对于货币类型,你将得到19.30而不是19.34。我不确定是否存在将钱分成1000份进行计算的应用场景,但这个示例确实暴露了一些局限性。