【问题标题】:Which SQL Server field type is best for storing price values?哪种 SQL Server 字段类型最适合存储价格值?
【发布时间】:2011-02-27 03:13:06
【问题描述】:

我想知道对于类似商店的结构,SQL Server 中价格字段的最佳类型是什么?

看看this overview,我们有称为moneysmallmoney的数据类型,然后是decimal/numeric,最后是float 真实的

名称、内存/磁盘使用情况和值范围:

  • 金钱: 8 个字节(值:-922,337,203,685,477.5808 到 +922,337,203,685,477.5807)
  • Smallmoney: 4 个字节(值:-214,748.3648 到 +214,748.3647)
  • 十进制: 9 [默认,最小。 5] 字节(值:-10^38 +1 到 10^38 -1)
  • 浮点数: 8 个字节(值:-1.79E+308 到 1.79E+308)
  • 实数: 4 个字节(值:-3.40E+38 到 3.40E+38)

在这些类型中存储价格值真的明智吗?例如呢。 INT?

  • 整数: 4 个字节(值:-2,147,483,648 到 2,147,483,647)

假设一家商店使用美元,他们有美分,但我不认为价格是 49.2142342 美元,所以使用大量小数来表示美分似乎浪费了 SQL 带宽。其次,大多数商店不会显示任何接近 200.000.000 的价格(至少在普通网上商店中不会,除非有人试图向我出售巴黎著名的塔楼)

那么为什么不选择 int 呢?

一个 int 很快,它只有 4 个字节,您可以轻松地进行小数化,方法是将值保存为美分而不是美元,然后在显示值时进行除法。

另一种方法是使用 4 字节的 smallmoney,但这将需要 CPU 的数学部分来进行计算,因为 Int 是整数幂...不利的一面是,您需要将每个单一结果。

在使用 smallmoney/money 字段时,区域设置是否存在与“货币”相关的问题?这些在 C#/.NET 中也会转移什么?

任何优点/缺点?选择整数价格还是 smallmoney 或其他?

你的经历说明了什么?

【问题讨论】:

  • 感谢您的所有回答!我有一种感觉,我们可能也会以这些结果结束。所以我很高兴你已经为我确认了这一点。我想我们会先从 smallmoney 开始。与其说是“存储空间”(价格),不如说是从磁盘反复传输到内存的数量或数据+每次连接和求和将有 4 个额外的字节来处理钱而不是小钱。所以我会看看我找到最好的答案,然后投票给你们中的一些人!感谢人们!真的!它的appriciated!
  • 用钱带来的四舍五入问题不容忽视。 @sqlvogel 的回答非常重要。

标签: c# sql-server linq-to-sql database-design query-optimization


【解决方案1】:

在我的当铺应用中,当铺经营者的贷款从 5.00 美元到 10,000.00 美元不等 当他们计算贷款金额时,他们将其四舍五入到最接近的美元,以便 避免处理美分(这同样适用于利息支付)。当贷款金额高于 50.00 美元时,他们会将其四舍五入到最接近的 5.00 美元(即 50 美元、55 美元、60 美元……),以尽量减少美元钞票的用完。因此,我对 transaction.calculated_loan_amount 使用 DECIMAL(7,2),对 transaction.loan_amount 使用 DECIMAL(5,0)。 该应用程序将贷款金额计算为一美分,并将该金额放在loan_amount 中,当低于 50 美元时,它会四舍五入到最接近的美元,如果更大,则四舍五入到最接近的 5.00 美元。

【讨论】:

    【解决方案2】:

    如果您绝对确定您的数字将始终保持在smallmoney 的范围内,那么使用它可以节省几个字节。否则,我会使用money。但请记住,这些天存储很便宜。 1 亿条记录 上的额外 4 个字节仍然不到半 GB。然而,正如@marc_s 指出的那样,如果可以的话,使用smallmoney 会减少SQL Server 的内存占用。

    长话短说,如果你能摆脱smallmoney,那就去做吧。如果您认为自己可能超过最大值,请使用money

    但是,不要使用浮点小数类型,否则您会遇到舍入问题,并且会开始丢失或获得随机美分,除非您正确处理它们。

    我反对使用 int 的论点:为什么要通过存储 int 来重新发明轮子,然后必须记住除以 100 (10000) 来检索值并在存储值时乘回。我的理解是货币类型无论如何都使用intlong 作为底层存储类型。

    就 .NET 中的相应数据类型而言,它将是 decimal(这也将避免 C# 代码中的舍入问题)。

    【讨论】:

    • 我同意重新发明轮子。问题是内存使用量与 cpu 功率对于连接上连接的大型事务的连接等。让我们说数百万行。但我认为“钱”或“小钱”毕竟是结论。好的。 :o)
    • @Ic:是的,现在磁盘存储很便宜-但是您选择的数据类型也会直接影响 SQL Server 的 RAM 消耗-它将磁盘页面以 1:1 的比例加载到 RAM 中-否压缩,没有位移动。因此,如果您在磁盘上浪费空间 - 您也在服务器内存中浪费了 spaec - 这并不像磁盘空间那么便宜......
    • @marc_s:这是我对这个问题的最初想法,但是如果我们使用 int 增加的开销似乎更糟,所以 smallmoney 可能是最好的答案
    • @BerggreenDK:当然,我同意 - 选择 SMALLMONEY。我只是想指出很多人没有考虑到的问题——选择数据类型也会影响服务器的 RAM 消耗——而不仅仅是所需的磁盘空间。
    • 嗯!刚刚偶然发现另一个关于 C# 中小数类型的讨论,它的 128 位 (stackoverflow.com/questions/618535/…) - 我猜不适合与 smallmoney 一起使用
    【解决方案3】:

    使用数字/小数。避免金钱/小钱。 Here's an example of why。由于舍入误差,MONEY / SMALLMONEY 类型迟早会让您失望。货币类型是完全多余的,没有任何用处 - 货币金额只是另一个十进制数字。

    最后,MONEY / SMALLMONEY 类型是 Microsoft 专有的。 NUMERIC / DECIMAL 是 SQL 标准的一部分。它们被更多人使用、认可和理解,并得到大多数 DBMS 和其他软件的支持。

    【讨论】:

    • 好吧,我认为我们不会除以 10000,所以我希望我们足够安全。其次,在测试中建议 NUMERIC(19,4),将使用 9 个字节 pr。价格标签。那是相当多的“额外”数据,以确保我不希望发生的事情的安全。在我看来,该特定测试的问题在于,您首先将数字分开,然后再相乘。如果您执行完全相反的操作: SET @mon4 = @mon1*@mon3/@mon2 那么您会得到相同的结果。我同意,它在测试和构建时需要我们的算法多一点,但我认为我们不会有问题。
    • MONEY 需要 8 个字节,等效的 DECIMAL 需要 9 个字节。SMALLMONEY 需要 4 个字节,等效的 DECIMAL 需要 5 个字节。我不会将 1 个字节描述为“相当多”。但也许我只是不明白你为什么要首先使用 MONEY/SMALLMONEY 类型。你认为它给你带来了什么好处?对于根本不是货币的十进制值,您会使用 MONEY 类型吗?如果不是,那为什么不呢?
    • MONEY 类型是从什么时候开始为 Microsoft 专有的?.. Informix 从 1983 年就开始使用它!
    • @Frank:我不知道 Informix。我的意思是 MONEY 是特定于供应商的扩展。它不是 SQL 标准的一部分。
    【解决方案4】:

    我会选择 Money 数据类型。个别你可能不会超过 Smallmoney 的价值,但多个项目很容易超过它。

    【讨论】:

      【解决方案5】:

      SQL 数据类型 moneysmallmoney 都解析为 c# decimal 类型:

      http://msdn.microsoft.com/en-us/library/system.data.sqltypes.sqlmoney(v=VS.71).aspx

      所以我想你不妨选择decimal。就个人而言,我一直在使用double 在金融行业工作,并且没有遇到过性能问题等。实际上,我发现对于某些计算等,拥有更大的数据类型允许更高的程度准确性。

      【讨论】:

        【解决方案6】:

        就我个人而言,我会用 smallmoney 或 money 来存储商店价格。

        在其他地方使用 int 会增加复杂性。

        2亿韩元或印尼卢比也是完全有效的价格......

        【讨论】:

          【解决方案7】:

          如果您要存储资金,请使用 Money 数据类型(除非对国债等巨额资金进行建模) - 它可以避免精度/舍入问题。

          The Many Benefits of Money…Data Type!

          【讨论】:

          • 而且由于您使用的是 C#,因此在您的 C# 代码中处理金钱时,请选择十进制数据类型。这将避免浮点/双精度数据类型通常会出现的舍入问题。
          • @Kevin 据我所知,Decimal 类型可能比使用 Double 和 Money 慢 20 倍,因为它的精度。我不确定它是一切的最佳选择。
          • 没有什么是最好的选择。你在和钱打交道。你概率。不希望舍入错误。例如,如果您将 10 x 10 美分添加到浮点数中,您会得到什么?从技术上讲,0.1 * 10 = 1。但是,如果您在调试器中查看这些 0.1 的总和,它是“1.00000012”。如果您想将其与 1 进行比较,除非您使用 epsilon 值,否则您不能。 docs.sun.com/source/806-3568/ncg_goldberg.html 我怀疑速度损失根本不是问题,除非你做的事情非常非常密集。它仍然非常快。毕竟,过早的优化是万恶之源。
          • @Kevin “过早的优化是万恶之源”——我明白了,但在我看来,从一开始就考虑正确的数据结构并不是过早的优化。它是关于在地表下建立一个坚实的基础。我认为在整个巨型 SQL 数据库 + 大量类中实现相同类型之前评估优缺点是可以的。我的问题也更多的是讨论哪种情况下的最佳实践。所以感谢您的意见,我真的很感谢您的时间。
          猜你喜欢
          • 1970-01-01
          • 2012-03-02
          • 1970-01-01
          • 2012-06-07
          • 2011-10-15
          • 2019-07-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多