今天我们在SQL查询中发现了一个奇怪的行为(我们使用MySQL v5.6.36和InnoDB).
拿这个查询:
mysql> SELECT count(*) FROM `inventory` WHERE `user_id` = 12345;
Run Code Online (Sandbox Code Playgroud)
它返回以下结果:
+----------+
| count(*) |
+----------+
| 495 |
+----------+
Run Code Online (Sandbox Code Playgroud)
但是当运行以下查询时:
mysql> SELECT count(*) FROM `inventory` WHERE `user_id` = 12345 AND list_type = 3;
Run Code Online (Sandbox Code Playgroud)
我们得到:
+----------+
| count(*) |
+----------+
| 1263 |
+----------+
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,当查询受到限制时,结果计数会更大,这不应该发生.可能是什么原因造成的?它仅在master数据库中发生,而两个复制数据库都显示正确的结果.我们怀疑索引已损坏.如何防止将来出现此类错误?
除了list_type返回无效(太高)之外的任何其他条件也是重要的.
不一致的结果可能意味着腐败的数据库或(如果幸运的话)腐败索引.尝试在不使用索引的情况下启动上述查询,看看你得到了什么:
SELECT count(*) FROM `inventory` USE INDEX () WHERE `user_id` = 12345;
SELECT count(*) FROM `inventory` USE INDEX () WHERE `user_id` = 12345 AND list_type = 3;
Run Code Online (Sandbox Code Playgroud)
如果这只是一个你可以尝试的索引
OPTIMIZE TABLE `inventory`;
Run Code Online (Sandbox Code Playgroud)
这将重新创建表和索引,然后对其进行ANALYZE.那是因为InnoDB不支持REPAIR TABLE.另一种选择可能是尝试添加相同的索引,然后删除原始索引.
要对表执行检查,您还可以使用CHECK TABLE,但如果要检查整个数据库,可以尝试
mysqlcheck --login-path=credentials --databases db_name
Run Code Online (Sandbox Code Playgroud)
并优化所有表格
mysqlcheck --login-path=credentials --optimize --databases db_name
Run Code Online (Sandbox Code Playgroud)
查看服务器的错误日志可能会提示您是否存在硬件问题或者您遇到的一些MySQL错误.
如果您的实际数据库已损坏,检查硬件然后尝试查看已损坏的内容以及如何通过与最近的备份进行比较来恢复它是有意义的.
小智 -4
有时 SQL 不能很好地处理“null”值。尝试这个:
mysql> SELECT count(*) FROM inventory WHERE (user_id = 12345 AND user_id is not null) AND (list_type = 3 AND list_type is not null);
Run Code Online (Sandbox Code Playgroud)
如果不起作用,请尝试将“*”替换为主键。例如:
mysql> SELECT count(user_id) FROM inventory WHERE (user_id = 12345 AND user_id is not null) AND (list_type = 3 AND list_type is not null);
Run Code Online (Sandbox Code Playgroud)
尽管 ifuser_id不能为“null”,但在这种情况下您不需要对此进行测试。