决定和后果
这是因为您决定使用浮点数据类型而导致的后果。浮点数不精确。这意味着:是的,您可以导致 a>a = true
例如,您的第四行:
mysql> SELECT * FROM t WHERE id=4;
+--------+--------+
| 编号 | 评级 |
+--------+--------+
| 4 | 973.88 |
+--------+--------+
一组中的 1 行(0.00 秒)
我已经留下了您发布的数据类型,它是FLOAT
. 我们到了:
mysql> 选择等级>973.88 FROM t WHERE id=4;
+---------------+
| 评分>973.88 |
+---------------+
| 1 |
+---------------+
一组中的 1 行(0.00 秒)
哎呀!
屏幕后面
为什么?要理解为什么会这样,您应该了解浮点数据类型是如何表示的。长篇大论就在这里。但是 - 我将简要概述一下。
这里它是如何表示的:哪里:
s
是标志
b
是基地。它的含义与基数相同
e
是指数。
这意味着我们可以用不同的方式表示一个数字——这取决于我们将选择哪个基数。最常见的是b=2
. 但并非所有实数都可以用这个底数精确表示,即使在十进制底下它们看起来“不错”。著名的例子是0.1
- 它不能b=2
精确地表示 - 所以它是近似存储的。再说一次,你可以在这里看到长篇大论- 但我只想指出,不可能用基数 2 精确地表示它。
结果是:即使数字在十进制基数中是精确的,它仍然可能无法精确表示 - 因此,它将被近似存储。这就是它的工作原理,事实上,这是有意的——因为浮动本身的结构。
该怎么办
固定精度
好吧,首先,您应该问自己:您真的需要 float吗?注意:我说:float。因为 - 还有定点数。它们将表示具有固定精度的数字。说得简单:使用定点数据类型,您可以确定您将准确存储您在屏幕上看到的内容。所以如果它是973.88
- 那么它是973.88
而不是973.8800000439234
。转移到交易:
mysql> ALTER TABLE t CHANGE rating rating DECIMAL(8,2);
查询正常,4 行受影响,4 个警告(0.47 秒)
记录:4 重复:0 警告:4
和 ..
mysql> 选择等级>973.88 FROM t WHERE id=4;
+---------------+
| 评分>973.88 |
+---------------+
| 0 |
+---------------+
一组中的 1 行(0.00 秒)
多田!魔术发生。您的号码现在以固定精度存储,因此,这种比较失败。
使用float
然后,当您遇到浮点数时,可能会有用例(但是,在 DBMS 的情况下,我什至很难记住一个这样的用例 - 如果不是大量计算的情况,这可能会导致性能影响,请参见下面的描述)。然后还有办法让它工作。您应该决定适合您的精度。那就是:从哪一点开始,您将平等对待数字。
你只存储两个有效数字,所以我认为精度1E-5
会绰绰有余。然后,您的查询将如下所示:
mysql> 设置@eps=1E-5;
查询正常,0 行受影响(0.00 秒)
并将其用于:
SELECT * FROM t WHERE rating>973.88+@eps
这将导致
+--------+---------+
| 编号 | 评级 |
+--------+---------+
| 1 | 1317.17 |
| 2 | 1280.59 |
| 3 | 995.12 |
+--------+---------+
哪个更好?
要意识到这一点,您需要再次查看掩护。我已经简要概述了什么是float
数据类型以及为什么它不精确。然而,fixed
数据类型也有它的弱点。也许这不是我们在 DBMS 上下文中应该担心的事情,但我会提到它:fixed
数据类型通常会导致性能影响。这取决于您将在 DBMS 中进行多少计算。
在 MySQL 中,fixed
-point 数据类型(例如DECIMAL
)被实现为BCD 字符串(长话短说 - 再次,这里是 wiki 链接)。这意味着与之相比float
会导致性能问题。但是,如果您不经常在 DBMS 中进行计算,那么这种影响甚至不会很明显——我已经提到过它,因为浮点和定点这两种类型都有自己的问题。
结论
DBMS,就像所有其他计算机的东西一样,并不完美。它只是使用一些内部的东西来完成工作。这意味着:在某些情况下,您必须了解内部事物是如何工作的,才能理解为什么会得到一些奇怪的结果。
特别是,浮点数并不精确。是的,互联网上有很多这样的答案,但我会重复一遍。它们并不精确。当涉及浮点数时,您不应该依赖精度。而且 - 在几乎所有 DBMS 中都有定点数据类型。而且 - 在像你这样的情况下,你应该使用它们。他们将做同样的工作,但有了他们,您将确定选定的精度。
但是,您可能想要使用浮点数 - 如果您要在 DBMS 中进行太多计算。但是,另一方面,那是关于 - 你为什么要这样做?为什么不使用应用程序来产生这些计算(因此,避免使用定点数据类型的性能影响和浮点数的精度问题 - 因为使用具有平均计算量的定点是可以的)