快乐学习
前程无忧、中华英才非你莫属!

Day19-解决MySQL_ERROR参考指南(问题排查-查询与可定制工具)

前面的章节已经介绍了许多问题排查技术与工具。对其中一部分工具,我进行了详细的剖析,而对于另一部分工具,我仅仅涉及了它们的使用。本章补充了前面章节尚未涉及的详细内容,我会尽量避免内容上的重复。很多技术与工具互相依赖,所以在本章中将把它们结合起来使用。有太多的工具需要详细介绍,但是篇幅有限,所以这里只介绍那些必需的工具。这些工具中的大部分都是命令行工具,要么来自于MySQL发布版,要么就是作为独立的包提供的。我还介绍一些第三方工具及其命令行使用方法。我这么做,并不是因为我不喜欢第三方工具,而是想让大家知道MySQL提供了很多非常强大的工具,并且你可以一直使用这些工具。MySQL工具的优势之一在于,它一直都是可用的,这对于客户来说是非常重要的。一些公司会有规定,禁止他们的员工下载第三方工具。因此,当我们进行技术支持时,我们总是偏爱使用MySQL发布版自带的工具。出于类似原因,这里不会介绍图形工具。命令行工具不需要特别的环境,例如,X Window System或特定的操作系统,而图形工具却会有更多的要求。最后,我确信MySQL的工具比其他包里类似的工具要更加优秀。假如你发现了更强大的第三方工具,也可以使用它们。但是,知道使用简单的工具能做什么总是非常有用的。
 
 
6.1 查询
 
第1章已经介绍了一条查询如何影响整个服务器的性能,以及如何找到哪一条语句出现了问题。这里将会针对这种类型的问题补充几句。由应用程序产生的有问题的查询,可以通过检查错误日志来定位。这可以通过使用应用程序中的输出函数来实现,这些输出函数自动记录了发送给MySQL服务器的查询,并使用了在应用程序和通用查询日志文件中针对这个目的所编写的一个库。这里介绍如何调整这些日志。通用日志文件缺少了一些帮助大家调试查询的重要信息,例如,查询执行时间、错误与警告信息、返回集信息。查询执行时间信息可以用来查找慢查询。当然,你可以使用一个自定义库或者通过在应用程序的任何位置简单地添加输出函数来记录所有这些特殊信息。但是在开始调试应用程序之前,你最好使用内置资源:慢查询日志。
 
6.1.1 慢查询日志
 
慢查询日志记录运行时间超过long_query_time秒的查询,该变量的默认值为10,但是可以减小它。实际上,可以将这个值设置为0来记录所有查询。从5.1版本以来,像通用查询日志那样,可以根据需要动态开启或关闭慢日志。也可以把输出从定向到表中,这样就能像其他数据那样查询表。为了做性能优化,我们需要找到最慢的查询,并单独地一条一条检查,然后改写这些查询语句或者做一些其他必要的改变,例如索引。为了发现更多的查询,可以从long_query_time默认值开始,一点一点减少,直至0。这种方法首先揭示了最慢的查询。默认情况下,这个选项不会记录管理语句和不用索引的快查询,但是可以分别设置log-slow-admin-statements和log_queries_not_using_indexes选项来记录这类查询。
 
慢查询日志的缺点之一是不能忽略你认为不需要优化的查询。把日志写到表中能帮助你过滤出自己不想看到的查询,因为你可以使用WHERE子句、分组和排序来把重点放到你认为重要的查询上。
 
mysqldump
slowmysqldumpslow工具可以以一种汇总格式输出慢查询日志中的内容。它将查询进行分组,所以如果两条查询字面上相同,但使用不同的参数,它们与执行次数只输出一次。这意味该工具把SELECT * FROM t2 WHERE f1=1与SELECT * FROMt 2 WHERE f1=2同样对待,因为f1参数的实际值通常不会影响查询的执行时间。如果你想在应用程序中找到同一类型却执行成千上万次的查询,该程序特别方便。 
 
 
 
 
 需要注意的是,尽管该工具足够智能,可以使用不同的参数来对相似的语句进行分组,但是即使语法上具
 
有微小的差别,它也会将这些语句视作不同的语句——例如,使用不同的大小写字母或不同的空格。
 
6.1.2 可定制的工具
 
一般情况,仅仅找到慢查询还不够。你需要知道更多,例如,返回哪些警告或错误,更新或者查询的行数。可以使用3种方法来获得这些信息:通过应用程序或编写插件或通过代理。应用程序可以使用1.4节介绍的方法来接收和记录信息;这里不再提供详细说明或者示例,因为它们主要取决于编程语言和其他上下文。如果查询执行时间,那么只需要在应用程序中调用mysql_query或mysql_real_query方法前后测量它。这种方法的优点是可调式。其缺点是需要修改应用程序,这对于使用第三方软件的用户来说是不可能的。如果出于审计的目的,你想编写一个MySQL服务器插件,那么可以参考MySQL参考手册中的“编写审计插件”(http://dev.mysql.com/doc/refman/5.5/en/writing-audit-plugins.html)一节。一旦安装,MySQL插件将变成MySQL服务器的一部分,并且能通过SQL查询访问。除了这个优点外,这种解决方案完全独立于应用程序,不需要更改已有代码,并能被多个应用程序使用。缺点是,它必须针对特定的MySQL服务器版本进行编译和安装,如果要把插件分发给更多用户,这就会比较麻烦。第三种解决方案是使用可脚本化的代理。代理是一个守护进程,它位于服务器与客户端之间,可以独立于服务器和客户端进行配置。因为它能获得所有流量,所以可以使用它做你想要做的任何事。这种方法的优点是你完全独立于服务端和客户端,因此无须改变你从别人那里接手的任何事情。其缺点是代理增加了额外的一层处理,所以它会降低应用程序的性能,并在客户端和服务器之间创建一个新的单点故障。MySQL代理MySQL代理是一个可脚本化的守护进程,它支持MySQL协议并位于MySQL服务器与应用程序之间。应用程序需要配置成所有查询经过代理的模式。这通常只需要设定适当的主机名和端口。MySQL代理支持Lua脚本语言。它允许查询重写和结果集重写、日志记录、负载平衡以及其他内容。这里只讨论日志,因为它能帮助我们调试慢查询。出于审计目的,你需要编写一个Lua脚本来保存必要的信息。以下给出了一个简单的脚本示例,它模拟通用查询日志行为,而且还保存查询执行时间。
 
可以改写这个脚本来满足自己的各种需求。在执行查询之前和之后,MySQL代理有权访问查询与结果集,与一般的通用日志文件相比,它允许用户记录更多信息:错误、警告、受影响的行数、查询执行时间,甚至完整返回集。在MySQL Forge中,可以发现很多有用的脚本。
 
6.1.3 MySQL命令行接口
 
MySQL命令行客户端,也称为MySQL CLI,是在大多数测试情况下使用的首要工具。当查询无法正常执行时,首先怀疑应用程序中有bug。但每个查询可能被众多问题影响,尤其是客户端和服务器选项。因此,如果你觉得自己发送了正确的查询却得到了错误的结果,就可以在MySQL CLI中测试该查询。这是验证你的猜测最简单且最快速的方法。当MySQL Support Bugs Verification Group(MySQL支持bug校验组)的成员怀疑客户端错误或(常见的)配置错误时,我们总是查找那些能够在MySQL CLI中测试的查询语句。这里将简单解释一下为什么这一点很重要,以及为什么其他工具不适合用于第一轮故障排除。  提示除了影响每个MySQL客户端应用程序的常用客户端参数外,Connector/J与Connector/ODBC都有它们各自的接口和参数。它们可以通过这些接口进行规则转换来影响查询语句。因此,如果你使用它们中的任意一个,那么在MySQL CLI中测试这些有问题的语句就会变得至关重要。为了测试应用程序返回的结果是否与你期望的一致,使用–column-type-info选项启动MySQL CLI,它会输出与数据类型相关的信息:
 
 
这个输出显示了与字段有关的基本元信息,如数据类型与排序规则等,可以通过配置选项或应用程序设置来改变这些信息。通过在MySQL CLI中运行它,你可以看到查询通常会在服务器上做些什么,并且如果服务器接收的信息与应用程序发出的不同,你就会推测这里出现了问题。现在让我们对输出信息逐行进行分析。
如果有,这表示标记。例如,主键字段会有PRI_KEY与AUTO_INCREMENT标记。
 
查询的结果集。如果你最喜欢的MySQL客户端并不是MySQL CLI,哪该怎么办?可以在这里进行测试,但是要记住,它可能会带来一些负面影响。特别是GUI面客户端。例如,如果客户端使用JDBC,那么它将受它的配置影响,但它的配置不会影响MySQL CLI。另一些客户端具有预设置字符集,如MySQL Workbench,它只支持UTF-8。这样的设置将阻止你测试其他字符集。一些客户端(如Workbench)会在每次查询之后断开连接并重新建立连接。而另一些客户端就会受到小的线程缓冲区影响,这对于基于Web的客户端来说非常常见。有时你可能会重新配置客户端,但是一旦遇到问题时,就更加容易切换到命令行并尝试在MySQL CLI中执行查询。
 
MySQL CLI的优势之一就是,与选项相比,它非常透明:你总能查看它的配置并对其进行调优。不可否认,MySQL CLI像任何软件一样也有bug,但通常有数以百万计的用户都在大规模使用该工具,并且Oracle公司内部也在积极使用它,因此你被MySQL CLI的bug影响到的概率是非常低的。  提示除了Connector/PHP之外,所有未配置的连接器最初都把character_ set_clients设置为UTF8,character_set_results设置为NULL。这实际上是一个“调试”模式的字符集,因此不建议在命令行客户端中使用。这种行为背后的原因是,让驱动程序逻辑确定显示结果到客户端和从客户端存储结果的最佳方式,并且通过防止服务器将文本结果转换成字符集结果来避免非常常见的“双重转换”bug。然而,对于即席查询这一招行不通,例如,SHOW CREATE TABLE,这个语句会把二进制看成UTF8,或SELECT varbinary_col FROM some_table,这里本身就是二进制类型,或SELECT CONCAT(char_field1,1)AS a,这里a将会有二进制标记集。
 
因此,所有连接器都会在它们的连接选项中用某种连接方法来告诉驱动程序用UTF8而不是二进制字符来处理函数返回值。同时,尽管每个连接器有自己的默认编码,但它们还是会执行SET NAMES UTF8。这主要是为了避免libmysqlclient库的默认行为,即将所有与字符集相关的变量设置为latin1。如果你认为一个查询应该执行正常,却返回了非期望的结果,那么在你认为它可能是MySQL服务器代码中的一个bug之前,请尝试在MySQL CLI中执行该语句。  提示我喜欢自动化。当我为bug记录创建测试时,我使用了一个脚本,该脚本在一组发布版MySQL服务器中(参见6.9.3节)运行MySQL Test Framework测试。这能帮助我用一条命令在很多版本中测试一个问题。但是这个习惯曾经让我出了一个冷笑话。我测试一个被提交的bug,但是我不能重现它,我花了很长时间与报告人沟通,我试了很多选项,遗憾的是,我完全依赖于我们的测试套件,并没有意识到该客户端可能会带来副作用。然后我的同事在MySQL CLI中尝试该测试用例,并得到与原报告人彻底相同的结果。该bug得到确认并被修复。这个经验告诉我们,忽视客户端可能的差异是多么危险,同时在做其他事情之前尝试使用MySQL CLI是多么重要。
 
打赏

未经允许不得转载:同乐学堂 » Day19-解决MySQL_ERROR参考指南(问题排查-查询与可定制工具)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

特别的技术,给特别的你!

联系QQ:1071235258QQ群:226134712
error: Sorry,暂时内容不可复制!