MySQL偶尔会返回错误的值

时间:2013-09-09 16:08:25

标签: php mysql

这是一个普遍的问题,我现在已经抓了一段时间了。我公司的数据库每天处理大约2k行。 99.9%的时间,我们对设置的不同SELECT语句中返回的值没有任何问题。但是,在非常罕见的情况下,我们的数据库将“出现故障”并返回与请求完全不同的行的值。

这是一个非常基本的例子:

+---------+-------------------------+
| row_id  | columnvalue             |
+---------+-------------------------+
|       1 | 10                      |
|       2 | 20                      |
|       3 | 30                      |
|       4 | 40                      |
+---------+-------------------------+

SELECT columnvalue FROM table_name WHERE row_id = 1 LIMIT 1

退货: 10

但是在非常罕见的情况下,它可能会返回:20或30等。

我完全不知道为什么它有时会这样做,并且会欣赏一些看似编程现象的见解。

更具体的信息:

SELECT
  USERID, CONCAT( LAST, ', ', FIRST ) AS NAME, COMPANYID 
FROM users, companies 
WHERE users.COMPANYCODE = companies.COMPANYCODE 
AND USERID = 9739 LIMIT 1

mysql> DESCRIBE users;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| USERID     | int(10)     | NO   | PRI | NULL    | auto_increment |
| COMPANYCODE| varchar(255)| NO   | MUL |         |                |
| FIRST      | varchar(255)| NO   | MUL |         |                |
| LAST       | varchar(255)| NO   | MUL |         |                |
+------------+-------------+------+-----+---------+----------------+

mysql> DESCRIBE companies;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| COMPANYID  | int(10)     | NO   | PRI | NULL    | auto_increment |
| COMPANYCODE| varchar(255)| NO   | MUL |         |                |
| COMPANYNAME| varchar(255)| NO   |     |         |                |
+------------+-------------+------+-----+---------+----------------+

结果假设是:9739,“L ----,E ----”,2197 取而代之的是:9739,“L ----,E ----”,3288

基本上,它根据公司代码的加入返回了错误的公司ID。鉴于我们公司的性质,我不能分享任何更多的信息。

我已经运行了这个查询5k次,并且已经对可想象的代码进行了非常修改,以便生成第二组结果,但我无法复制它。我不是很快责怪MySQL - 这已经发生了(虽然很少)超过8年,并已经用尽所有其他可能的原因。我怀疑在运行查询后手动更改了结果,但是时间戳另有说明。

我只是想知道为什么在500k次中它可以完美地运行499k。

3 个答案:

答案 0 :(得分:3)

现在我们有一个更现实的查询,我立即注意到你正在加入表,而不是主键,而是公司代码。我们是否确定公司代码被强制执行为公司的唯一索引?如果找到这样的行,限制1将隐藏第二行。

从设计的角度来看,我会在主键上进行连接,以避免重复键的可能性,并将公司代码作为唯一的索引字段放在显示和查找中。

答案 1 :(得分:2)

这种行为要么是由于MySQL中一个令人难以置信的不太可能的 SERIOUS错误, - 或者 - MySQL正在返回在语​​句运行时有效的结果,并且还有一些其他软件正在扼杀显示的结果。

考虑的一种可能性是在执行SQL语句时已经修改了行(通过其他语句),然后稍后再次更改行。 (这是我们对MySQL返回意外结果的最可能的解释。)

使用LIMIT 1子句很奇怪,因为如果谓词唯一标识一行,则不需要LIMIT 1,因为查询保证不会返回一行

这使我怀疑row_id不是唯一的,并且查询实际上返回了多行。使用LIMIT子句,无法保证返回哪些行(缺少ORDER BY子句。)

否则,最可能的罪魁祸首是过时的缓存内容或代码中的其他问题。


更新

之前的答案基于给出的示例查询;我有意地省略了EMP是一个正在进行JOIN的视图的可能性,因为问题最初说它是一个表,示例查询只显示了一个表。

根据问题中的新信息,我建议你从查询中查看LIMIT 1子句。这将标识查询返回多行。

从表定义中,我们看到数据库没有对COMPANY表中的COMPANYCODE列强制执行UNIQUE约束。

由于数据类型不匹配,我们也知道没有定义外键。

通常,外键将定义为引用目标表的PRIMARY KEY。

我们希望users表具有company_id列,该列引用id表中的companies(主键)列。

(我们注意到companycode列(int)的数据类型与companies表中主键列的数据类型匹配,我们注意到连接条件是匹配的companycode列,即使数据类型不匹配,这也很奇怪。)

答案 2 :(得分:1)

这可能有几个原因。我建议你看看你正在做的假设。例如:

  • 如果您正在使用GROUP BY且其中一列不是聚合或分组表达式,那么您将在该列中获得不可预测的值。确保使用适当的聚合(例如MAXMIN)以在每列上获得可预测的结果。
  • 如果您假定行顺序而不明确,并且使用LIMIT仅获取第一行,则实际返回的行顺序会根据结果的执行计划而有所不同,执行计划会有所不同。基于优化程序可用统计信息的大型结果集。确保在这种情况下使用ORDER BY