每个 MySQL 版本在发布之前都会在许多平台上进行测试。这并不意味着 MySQL 中没有错误,但如果有错误,它们应该很少,并且很难找到。如果您遇到问题,尝试找出究竟是什么导致系统崩溃总是有帮助的,因为您有更大的机会快速解决问题。
首先,您应该尝试确定问题是 mysqld 服务器崩溃还是与您的客户端有关。您可以通过执行 mysqladmin version 来检查 mysqld 服务器的运行时间。如果 mysqld 已崩溃并重新启动,您可以在服务器的错误日志中找到原因。请参阅 第 7.4.2 节“错误日志”。
在某些系统上,您可以在错误日志中找到 mysqld 崩溃位置的堆栈跟踪。请注意,错误日志中写入的变量值可能并不总是 100% 正确。
如果您发现 mysqld 在 InnoDB
恢复期间启动失败,请参阅 第 17.20.2 节“故障排除恢复失败”。
许多意外的服务器退出是由损坏的数据文件或索引文件引起的。MySQL 在每个 SQL 语句之后和客户端收到结果通知之前,使用 write()
系统调用更新磁盘上的文件。(如果您在启用了 delay_key_write
系统变量的情况下运行,则情况并非如此,在这种情况下,数据文件会被写入,但索引文件不会。)这意味着即使 mysqld 崩溃,数据文件内容也是安全的,因为操作系统会确保将未刷新的数据写入磁盘。您可以通过使用 --flush
选项启动 mysqld,强制 MySQL 在每个 SQL 语句之后将所有内容刷新到磁盘。
以上内容意味着,除非发生以下情况之一,否则通常不会出现损坏的表:
MySQL 服务器或服务器主机在更新过程中被终止。
您在 mysqld 中发现了一个错误,导致它在更新过程中崩溃。
某些外部程序在 mysqld 运行时,在没有正确锁定表的情况下操作数据文件或索引文件。
您在一个不支持良好文件系统锁(通常由
lockd
锁管理器处理)的系统上运行多个使用相同数据目录的 mysqld 服务器,或者您在禁用外部锁定的情况下运行多个服务器。您有一个崩溃的数据文件或索引文件,其中包含非常混乱的数据,导致 mysqld 出现混乱。
您在数据存储代码中发现了一个错误。这不太可能,但至少有可能。在这种情况下,您可以尝试通过对修复后的表副本使用
ALTER TABLE
将存储引擎更改为其他引擎。
因为很难知道是什么原因导致崩溃,所以首先尝试检查对其他人有效的东西是否会导致您遇到意外退出。尝试以下操作:
使用 mysqladmin shutdown 停止 mysqld 服务器,从数据目录运行 myisamchk --silent --force */*.MYI 以检查所有
MyISAM
表,然后重新启动 mysqld。这可以确保您从一个干净的状态开始运行。请参阅 第 7 章“MySQL 服务器管理”。在启用常规查询日志的情况下启动 mysqld(请参阅 第 7.4.3 节“常规查询日志”)。然后尝试从写入日志的信息中确定是哪个特定查询导致服务器崩溃。大约 95% 的错误都与某个特定查询有关。通常,这是服务器重新启动之前日志文件中的最后几个查询之一。请参阅 第 7.4.3 节“常规查询日志”。如果您可以在发出某个特定查询之前检查所有表,但仍然可以重复导致 MySQL 崩溃,那么您已经隔离了该错误,应该为此提交错误报告。请参阅 第 1.6 节“如何报告错误或问题”。
尝试创建一个我们可以用来重现问题的测试用例。请参阅 第 7.9 节“调试 MySQL”。
尝试运行
fork_big.pl
脚本。(它位于源代码发行版的tests
目录中。)配置 MySQL 以进行调试,以便在出现问题时更轻松地收集有关可能错误的信息。使用
-DWITH_DEBUG=1
选项重新配置 MySQL 到 CMake,然后重新编译。请参阅 第 7.9 节“调试 MySQL”。确保您已为您的操作系统应用了最新的补丁。
对 mysqld 使用
--skip-external-locking
选项。在某些系统上,lockd
锁管理器无法正常工作;--skip-external-locking
选项告诉 mysqld 不要使用外部锁定。(这意味着您不能在同一个数据目录上运行两个 mysqld 服务器,并且在使用 myisamchk 时必须小心。尽管如此,尝试使用该选项作为测试可能会有所帮助。)如果 mysqld 看起来正在运行但没有响应,请尝试 mysqladmin -u root processlist。有时 mysqld 并没有挂起,即使它看起来没有响应。问题可能是所有连接都在使用中,或者可能存在一些内部锁问题。mysqladmin -u root processlist 通常能够在这些情况下建立连接,并且可以提供有关当前连接数及其状态的有用信息。
在单独的窗口中运行命令 mysqladmin -i 5 status 或 mysqladmin -i 5 -r status,以便在运行其他查询时生成统计信息。
尝试以下操作
从 gdb(或其他调试器)启动 mysqld。请参阅 第 7.9 节 “调试 MySQL”。
运行您的测试脚本。
打印最低三层的回溯和局部变量。在 gdb 中,当 mysqld 在 gdb 内部崩溃时,可以使用以下命令执行此操作
backtrace info local up info local up info local
使用 gdb,您还可以使用
info threads
检查哪些线程存在,并使用thread
切换到特定线程,其中N
N
是线程 ID。
尝试使用 Perl 脚本模拟您的应用程序,以强制 MySQL 退出或出现异常行为。
发送正常的错误报告。请参阅 第 1.6 节 “如何报告错误或问题”。比平时更加详细。因为 MySQL 对许多用户都有效,所以崩溃可能是由您的计算机上才有的东西引起的(例如,与您的特定系统库相关的错误)。
如果您在包含动态长度行的表中遇到问题,并且仅使用
VARCHAR
列(不使用BLOB
或TEXT
列),则可以使用ALTER TABLE
将所有VARCHAR
更改为CHAR
。这会强制 MySQL 使用固定大小的行。固定大小的行会占用一些额外的空间,但对损坏的容忍度要高得多。当前的动态行代码已经使用了几年,很少出现问题,但动态长度行本质上更容易出错,因此尝试这种策略看看它是否有帮助可能是个好主意。
在诊断问题时,请考虑硬件故障的可能性。硬件缺陷可能是数据损坏的原因。在对硬件进行故障排除时,请特别注意您的内存和磁盘子系统。