每个 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 的同时操作数据文件或索引文件,但没有正确锁定表。
您正在多个系统上运行多个 mysqld 服务器,这些服务器使用同一个数据目录,而该系统不支持良好的文件系统锁(通常由
lockd
锁管理器处理),或者您在禁用外部锁定的情况下运行多个服务器。您有一个崩溃的数据文件或索引文件,其中包含非常混乱的数据,导致 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,然后重新编译。请参阅 第 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 使用固定大小的行。固定大小的行会占用一些额外的空间,但对损坏的容忍度要高得多。当前的动态行代码已经使用了几年,很少出现问题,但动态长度行本质上更容易出现错误,因此尝试此策略以查看它是否有帮助可能是一个好主意。
在诊断问题时,请考虑硬件故障的可能性。有缺陷的硬件可能是数据损坏的原因。在对硬件进行故障排除时,请特别注意您的内存和磁盘子系统。