为什么我的查询是不确定的?
我有执行以下操作的查询:
select sum(float1*float2*coalesce(float3,1)) from table
当我运行这个查询时,我得到了一个确定性的结果,但当查询运行多次时,情况似乎并非如此。
结果中的最后一个整数在不同的运行之间有所不同。
所有列都是 (float,null)
所有运行的浮点截断都应该相同吗?
为什么我的查询是不确定的?
我有执行以下操作的查询:
select sum(float1*float2*coalesce(float3,1)) from table
当我运行这个查询时,我得到了一个确定性的结果,但当查询运行多次时,情况似乎并非如此。
结果中的最后一个整数在不同的运行之间有所不同。
所有列都是 (float,null)
所有运行的浮点截断都应该相同吗?
乘以近似值会乘以误差:有时它们会抵消但通常它们会夸大
float最多也精确到15 位有效数字 :当你乘法和SUM 时,你可以快速命中它并失去准确性。
我想结果的变化将取决于访问数据的顺序(例如新行、行溢出、页面拆分等的变化),因此所涉及的一系列计算将改变顺序,每个顺序都有自己的舍入。
编辑:有一个想法。
每个核心/插槽将以不同的方式进行浮动计算。
试试这些,看看我们是否可以确定这一点(注意这与“正确”不同)
将 MAXDOP 1 添加到查询中,看看您得到了多少不同的结果。我期望的不仅仅是内核或插槽的数量。这减少了并行排列的数量
然后尝试处理器亲和性以始终对所有查询使用相同的核心,以强制查询在一个核心/CPU 上运行
要修复它,请使用 decimal 或 bigint。
正如其他人所提到的,浮点数几乎是不确定的。不幸的是,您对此无能为力。
例如,如果将数字 5 放入表中然后将其截断,最终可能会得到 4.000,因为 5 最终可能在内存中表示为 4.9999。
如果您尝试通过四舍五入来解决这个问题,这与 5.5 实际上可能存储为 5.49999 的问题相同,这将四舍五入为 5。
您可以尝试一些小技巧,例如添加 0.25 然后截断,但我认为这完全忽略了 FLOATS 的要点。
最终,它们——就其自身而言——是相当不确定的。有趣的是,这是体系结构的一个问题,并将传播到操作系统(意味着所有语言和应用程序,包括数据库)中对浮点数的所有使用。
我的第一个想法是因为 float 是一个近似数字,使它成为一个不确定的函数。
Float不是精确的数据类型。