3

这是一个普遍的问题,我一直在摸索一段时间。我公司的数据库每天处理大约 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。

4

3 回答 3

3

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

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

于 2013-09-09T17:22:34.570 回答
2

这种行为要么是由于 MySQL 中的一个非常不可能的严重错误,要么是 MySQL 返回的结果在语句运行时有效,并且还有一些其他软件正在篡改显示的结果。

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

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

这使我怀疑这row_id不是唯一的,并且查询实际上返回了不止一行。使用 LIMIT 子句,不能保证将返回哪些行(没有 ORDER BY 子句。)

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


更新

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

根据问题中的新信息,我建议您LIMIT 1从查询中省略该子句。这将确定查询返回多于一行。

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

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

通常,外键将通过引用目标表的主键来定义。

我们期望users表有一个company_id列,它引用表中的id(主键)列companies

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

于 2013-09-09T16:22:40.300 回答
1

发生这种情况有几个原因。我建议你看看你所做的假设。例如:

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