前言
MySQL是一个专业、复杂、成熟、强大的数据库系统,可以满足大量客户的需求。MySQL 的安装和配置都很简单。
事实上,大部分默认安装根本不需要任何配置。然而,MySQL 作为一个拥有众多功能层次的系统,有时也会有故障,会产生警告甚至错误。有时候,这些警告和错误提供的信息明确(比如,你可能经历过或者在文档中有记录),足以帮助你立即解决问题。也有时候,你遭遇的问题没有已知的解决方案,或者该问题是与你的应用、数据库环境相关的特定问题。
寻找这类警告、错误或者其他MySQL问题的解决方案可以说是一项让人望而却步的工作。当遭遇这种问题的时候,数据库专家一般都从各种各样的资料或者记录过相似问题和解决方案的文档中查找线索。大多数时候,你会发现针对问题的建议繁多且相似,或者其中给出的解决方案对你的情况并不适用。针对这种情形,人们普遍的做法是在互联网上搜索错误消息。通常,你会搜索到各种各样的信息,包括从电子邮件的归档到个人博客,甚至是一些可能与错误消息相关或者不相关的评论。这往往很浪费时间而且容易造成困惑。你需要的其实是一个可以告诉你如何解决MySQL问题的参考指南。
一、基础
1、1 语法错误
这个错误听起来十分简单,但仍可能很难发现。我建议你像处理其他问题一样,非常细心地查找可能出现的SQL语法错误。类似如下错误,很容易被发现:
SELECT * FRO t1 WHERE f1 IN(1,2,1);
在这个示例中,很显然用户少转入了个“m”,错误消息也很清楚(输出结果根据页面设置进行宽度调整):
遗憾的是,不是所有的语法错误都这么显而易见。我曾经处理过一个问题,它的查询语句是这样的:
这是一个版本迁移导致的问题;该语句在5.0版本中运行正常,但是在5.1版本中出现错误。问题的原因在于,在5.1版本中,“accessible”是一个保留字。给该语句加上引号(反引号还是双引号取决于你的SQL格式),即可重新正常运行:
实际场景中的查询语句看起来可能十分繁琐,包括大段的JOIN和复杂的WHERE条件。所以,即使是简单的错误在其他大量语句的干扰下也很难被查找出来。我们当时第一步的任务就是简化复杂的查询,使它变成像刚才看到的那样只有一行SELECT的语句。这就是一个最简化测试的示例。当我们看到简化后只有一行的语句也有同样的bug时,我们就能很快意识到原有程序是因为保留字的问题而产生了错误。
- 第一教训就是教你把检查查询的语法错误作为排错的第一步。
但是,当你不知道查询是什么样的时候该怎么办?比如,查询是由应用程序自动生成的,或是在存储库中由第三方库动态生成的。
考虑如下PHP代码:
从这段脚本中很难直接定位错误。幸运的是,我们可以通过调整代码,使用输出函数打印查询语句。在PHP语言中,可以使用echo运算符。因此,修改代码,如下所示:
当程序输出将要提交的语句的时候,问题暴露出来了:
如果你仍然没有发现错误,你可以在MySQL命令行客户端中尝试执行这个查询:
问题在于每一行都少了一个右单引号。返回PHP代码,需要把:
改为:
即可。
- 因此,一个重要的调试技巧是,始终尝试查看MySQL服务器最终接收到的查询。不要仅调试应用程序代码,要获取查询语句!
遗憾的是,你不可能始终使用输出函数。比如,我之前提到的那个场景,SQL语句是在编译好的第三方库中生成的。你的应用程序可能只是使用了库提供的高级的抽象接口,比如CRUD(新建、读、更新、删除)接口。或者在生产环境下,你不希望用户看到在使用特定参数对特定查询进行测试时的查询。在这种情况下,可以检查MySQL的通用查询日志。这里用一个新示例来说明其是如何工作的。
这是一段有问题的PHP代码:
这段代码更新了例1.1中定义的表。
例1.1 一般问题情形的示例表
现在启用通用查询日志。该日志包含MySQL服务器接收到的每条独立查询。很多产品不会在日常运行中使用该日志,因为它在高负载的情况下增长十分迅速,并且写入日志会消耗MySQL服务器的资源,这些资源很可能用于更重要的用途。从5.1版本开始,你可以临时打开通用查询日志,方便随时记录你需要的查询。可以通过下面命令打开日志:
也可以将日志记录在表中,这可以帮你方便地分类索引日志文件项,因为你可以像查询其他表一样访问查询日志表:
现在可以运行应用程序。经过迭代地执行问题代码后,查询通用日志记录表,以查找有问题的查询:
注意上述代码中2.row中的查询语句:
错误再次显而易见:在语句的结尾有个多余的逗号。这个问题是由下面这部分PHP代码产生的:
如果字符串确实是以逗号结尾的,那么rtrim函数本应移除结尾的逗号。但是现在这行实际上是以空格结尾的,因此rtrim函数没有移除任何字符。
既然我们已经发现了应用程序中产生错误的原因,我们就可以关闭通用查询日志:
在这节,我们学到一些重要的东西:
- 语法错误可能是导致一些现实问题的原因;
- 你应该测试与MySQL服务器接收到的请求完全一致的查询;
- 编程语言的输出函数和通用查询日志可以帮助你快速定位由应用程序发送到MySQL服务器的查询的问题。
这是用户反馈的另一个非常常见的问题,主要的现象有:用户看不到更新的结果、展示的顺序错误或者查询到了非预期的结果。这个问题主要有两方面的原因:一方面是你的SELECT查询有误;另一方面是数据库中的数据和你想象的不同。我先介绍第一种情况。在我规划本节示例的时候,我考虑要么使用真实的示例,要么使用我自己设计的小场景。真实的示例可能占用大量篇幅,但是我自己设计的示例可能对你没有什么帮助,因为没有人会写出那样的代码。因此,我选择使用典型的真实示例作为示例,只是大幅简化了它们。
本文摘自《MySQL排错指南》 斯米尔诺娃