这是一个普遍的问题,我现在已经抓了一段时间了。我公司的数据库每天处理大约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。
答案 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
且其中一列不是聚合或分组表达式,那么您将在该列中获得不可预测的值。确保使用适当的聚合(例如MAX
或MIN
)以在每列上获得可预测的结果。LIMIT
仅获取第一行,则实际返回的行顺序会根据结果的执行计划而有所不同,执行计划会有所不同。基于优化程序可用统计信息的大型结果集。确保在这种情况下使用ORDER BY
。