海浪家园

检查、优化和修复MYSQL数据库

MySql数据库修复
                                      

今天早上发现因为磁盘满造成了Mysql服务没法正常运行,首先腾硬盘空间,再停止 mysqld服务,还用了下kill杀掉了mysqld进程,后来发现数据库虽然启动了,但是数据表损坏了,google搜索了下,用myisamchk 修复了下数据表文件,成功。特摘录下文。

检查和修复MySQL数据文件

由于临时断电,使用kill -9中止MySQL服务进程,或者是Jessica的朋友idiot@%.host.net又犯了一个错误,所有的这些都可能会毁坏MySQL的数据文件。如果在被干扰时,服务正在改变文件,文件可能会留下错误的或不一致的状态。因为这样的毁坏有时是不容易被发现的,当你发现这个错误时可能是很久以后的事了。于是,当你发现这个问题时,也许所有的备份都有同样的错误。

MySQL参考手册的第十五章讲述了MySQL自带的myisamchk的功能,以及如何使用它检查和修复你的MySQL数据文件。虽然这一章对于每个想要搭建一个强壮的MySQL服务的人都是推荐阅读的,我们还是有必要在这里对其中的要点进行讨论。

在我们继续之前,你必须意识到myisamchk程序对用来检查和修改的MySQL数据文件的访问应该是唯一的。如果MySQL服务正在使用某一文件,并对myisamchk正在检查的文件进行修改,myisamchk会误以为发生了错误,并会试图进行修复–这将导致MySQL服务的崩溃!这样,要避免这种情况的发生,通常我们需要在工作时关闭MySQL服务。作为选择,你也可以暂时关闭服务以制作一个文件的拷贝,然后在这个拷贝上工作。当你做完了以后,重新关闭服务并使用新的文件取代原来的文件(也许你还需要使用期间的变更日志)。

MySQL数据目录不是太难理解的。每一个数据库对应一个子目录,每个子目录中包含了对应于这个数据库中的数据表的文件。每一个数据表对应三个文件,它们和表名相同,但是具有不同的扩展名。tblName.frm文件是表的定义,它保存了表中包含的数据列的内容和类型。tblName.MYD文件包含了表中的数据。tblName.MYI文件包含了表的索引(例如,它可能包含lookup表以帮助提高对表的主键列的查询)。

要检查一个表的错误,只需要运行myisamchk(在MySQL的bin目录下)并提供文件的位置和表名,或者是表的索引文件名:

% myisamchk /usr/local/mysql/var/dbName/tblName
% myisamchk /usr/local/mysql/var/dbName/tblName.MYI

上面的两个命令都可以执行对指定表的检查。要检查数据库中所有的表,可以使用通配符:

% myisamchk /usr/local/mysql/var/dbName/*.MYI

要检查所有数据库中的所有表,可以使用两个通配符:

% myisamchk /usr/local/mysql/var/*/*.MYI

如果不带任何选项,myisamchk将对表文件执行普通的检查。如果你对一个表有怀疑,但是普通的检查不能发现任何错误,你可以执行更彻底的检查(但是也更慢!),这需要使用–extend-check选项:

% myisamchk –extend-check /path/to/tblName
对错误的检查是没有破坏性的,这意味着你不必担心执行对你的数据文件的检查会使已经存在的问题变得更糟。另一方面,修复选项,虽然通常也是安全的,但是它对你的数据文件的更改是无法撤消的。因为这个原因,我们强烈推荐你试图修复一个被破坏的表文件时首先做个备份,并确保在制作这个备份之前你的MySQL服务是关闭的。

当你试图修复一个被破坏的表的问题时,有三种修复类型。如果你得到一个错误信息指出一个临时文件不能建立,删除信息所指出的文件并再试一次–这通常是上一次修复操作遗留下来的。

这三种修复方法如下所示:

% myisamchk –recover –quick /path/to/tblName
% myisamchk –recover /path/to/tblName
% myisamchk –safe-recover /path/to/tblName

第一种是最快的,用来修复最普通的问题;而最后一种是最慢的,用来修复一些其它方法所不能修复的问题。

检查和修复MySQL数据文件

如果上面的方法无法修复一个被损坏的表,在你放弃之前,你还可以试试下面这两个技巧:

如果你怀疑表的索引文件(*.MYI)发生了不可修复的错误,甚至是丢失了这个文件,你可以使用数据文件(*.MYD)和数据格式文件(*.frm)重新生成它。首先制作一个数据文件(tblName.MYD)的拷贝。重启你的MySQL服务并连接到这个服务上,使用下面的命令删除表的内容:

mysql> DELETE FROM tblName;

在删除表的内容的同时,会建立一个新的索引文件。退出登录并重新关闭服务,然后用你刚才保存的数据文件(tblName.MYD)覆盖新的(空)数据文件。最后,使用myisamchk执行标准的修复(上面的第二种方法),根据表的数据的内容和表的格式文件重新生成索引数据。

如果你的表的格式文件(tblName.frm)丢失了或者是发生了不可修复的错误,但是你清楚如何使用相应的CREATE TABLE语句来重新生成这张表,你可以重新生成一个新的.frm文件并和你的数据文件和索引文件(如果索引文件有问题,使用上面的方法重建一个新的)一起使用。首先制作一个数据和索引文件的拷贝,然后删除原来的文件(删除数据目录下有关这个表的所有记录)。

启动MySQL服务并使用当初的CREATE TABLE文件建立一个新的表。新的.frm文件应该可以正常工作了,但是最好你还是执行一下标准的修复(上面的第二种方法)。

理想的情况是,mysql从首次安装以来始平稳地运行。但有时确实会由于各种原因而出现问题,其范围可以从电源断电到硬件故障到不正常地关闭mysql 服务器(如用kill -9 终止服务器或机器崩溃)。诸如这样的情况大部分都超出您的控制范围,它们会导致数据库表的毁坏,尤其是在对表进行修改且未完全写入时所引起的。

  本章的重点是检测和解决表的问题,而不论问题是如何引起的。对于表的检查和修复,mysql管理员最好的朋友是myisamchk 和isamchk 实用程序。这两个程序有好几个功能,我们已经在第4章讨论了怎样使用它们执行索引键的分布分析和索引的释放与激活。还可以使用它们检查表和修复有问题的表。这使您能在表变坏之前(使表不能使用之前)修正故障。
  myisamchk 和isamchk 提供的全部选项的清单在附录e 中。有关其他的背景,请参阅mysql参考指南的“维护mysql安装”一章。

  表的故障检测和修正的一般过程如下:
  1) 检查出错的表。如果该表检查通过,则完成任务,否则必须修复它。
  2) 在开始修复之前对表文件进行拷贝,以防万一。
  3) 试着修复表。
  4) 如果修复操作失败,从数据库备份和更新日志中恢复此表。
  上述过程的最后一步假定您已经执行了数据库备份并允许更新日志有效。如果不是这样的话,系统将有危险。参考第11章查找一下怎样使用mysqlaump 和怎样开启更新日志。您肯定不想不可挽回地丢失一个表,因此,应努力地做备份。
  在使用myisamchk 或isamchk 检查或修复表之前,应该满足一些初步需求:
  建立常规的数据库备份过程并允许更新日志,以防事情越来越糟使表的毁坏不能修复。笔者好像在以前提醒过这一点?
  在开始试验之前应先仔细地阅读本章的内容。尤其是不应该在阅读“避免与mysql服务器交互作用”之前进行操作,因为它将讨论当您试图在一个表上执行检查或修复过程时服务器正在使用这个表所引起的问题。它还讨论怎样在服务器运行时防止那些问题发生。
  当运行表检查或修复时,您应该被注册在运行mysql的账号下,因为您需要对表文件读写访问。
  

myisamchk 和isamchk 的调用语法

  mysql的myisamchk 和isamchk 实用程序很类似,多数时候它们可以用同样的方式使用。它们之间的主要区别是它们所使用的表的类型。对于myisam 表,使用my i s a m c h k,而对于isam 表,则使用i s a m c h k。您可以通过表的索引文件的扩展名来告诉表使用哪种存储格式。扩展名“. m y i”表明是一个myisam 表,而“. i s m”表明是isam 表。
  为了使用任一个实用程序,应指明您所要检查或修复的表,以及指明要执行的操作类型的选项:
  % myisamchk options tbl_name…
  % isamchk options tbl_name…
  tbl_name 参数可以是表名也可以是该表的索引文件名。如果指定多个表,可以很容易地使用文件名模式来拾取目录中所有相应的文件:
  % myisamchk options *.myi
  % isamchk options *.ism
  不会因为告诉了错误的程序来检查某个表而使该表毁坏,但是除了发布一条警告消息外此程序不做任何事情。例如,下面的第一条语句将检查当前目录中的所有myisam 表,而第二条语句只显示一条警告消息:
  % myisamchk *.myi 正确
  % myisamchk *.ism 不正确─文件类型错
  不论是myisamchk 还是isamchk 都不对表所在的位置做任何判断,因此,应该或者在包含表文件的目录中运行程序,或者指定表的路径名。这允许您将表文件拷贝到另一个目录中并用该拷贝进行操作。

检查表

  myisamchk 和isamchk 提供了表检查方法,这些方法在彻底检查表的程度方面有差异。通常用标准方法就足够了。如果标准检查报告没有发现错误而您仍然怀疑有毁坏(或许因为查询没有正常地工作),可能要执行更彻底的检查。要想用任意一个实用程序执行标准的表检查,则不用带任何选项直接调用即可:
  % myisamchk tbl_name
  % isamchk tbl_name
  为了执行扩充检查,使用–extend-check 选项。该选项非常慢,但检查极为彻底。对于该表的数据文件中的每个记录,索引文件中的每个索引的相关键都被检查以确保它真正指向正确的记录。 myisamchk 还有一个中间选项- – m e d i um – c h e c k,它不如扩展检查彻底,但速度快。
  如果对于–extend-check 检查不报告错误,则可以肯定表是好的。如果您仍然感觉表有问题,那原因肯定在其他地方。应重新检查任何好像有问题的查询以验证查询是正确书写的。如果您认为问题可能是mysql服务器的原因,应考虑整理一份故障报告或升级到新的版本上。
  如果myisamchk 或isamchk 报告表有错误,应用下节中的说明修复它们。

修复表

  表的修复是一项可怕的工作,如果具体问题非常独特则更难进行。然而,有一些常规的指导思想和过程,可以遵循它们来增加修正表的机会。通常,开始时可以用最快的修复方法,看看是否能修正故障。如果发现不行的话,可以逐步升级到更彻底的(但更慢的)修复方法上,直到故障被修复或您不能继续升级为止(实际上,大多数问题不用更大规模的和更慢的方法就能修正)。如果表不能修复,则从备份中恢复该表。有关使用备份文件和更新日志进行恢复的指导在已第11章中给出。
  1. 执行标准的表修复
  为了修复一个表,执行下列步骤:
  1) 试着用–recover 选项修正表,但也可以用–quick 选项试图只根据索引文件的内容进行恢复。这样将不触及数据文件:
  % myisamchk –recover –quick tbl_name
  % isamchk –recover –quick tbl_name
  2) 如果问题仍存在,再试一下上一步的命令,但忽略–quick 选项,以允许my i s a m c h k或isamchk 前进并修改数据文件:
  % myisamchk –recover tbl_name
  % isamchk –recover tbl_name
  3) 如果还不工作,试一试–safe-recover 修复方法。这种方法比普通的恢复方法要慢,但能够修正-recover 方法不能修正的几个问题:
  % myisamchk –safe-recover tbl_name
  % isamchk –safe-recover tbl_name
  如果myisamchk 或isamchk 由于一个“c a n’t create new temp file: file_name” 的错误消息在任何一步中停止,应该重复这个命令并增加–force 选项以迫使清除临时文件。这个临时文件可能是从上一次失败的修复中留下的。
  在修复表之前拷贝它们在执行表修复前应该遵循的一个常规的预防措施是做该表的新拷贝。这种情况未必出现,但如果发生,则可以从拷贝文件中做该表的新的拷贝并试试另一种恢复方法。
  2. 标准表修复方法失败时怎么办
  如果标准的修复过程未能修复表,则索引文件可能在修复时丢失或毁坏。尽管未必可能,但还是有可能使表的描述文件丢失。不论哪种情况,都需要替换受影响的文件,然后再试试标准修复过程。
  为了重新生成索引文件,可以使用下列过程:
  1) 定位到包含崩溃表的数据库目录中。
  2) 将该表的数据文件移到安全的地方。
  3) 调用mysql并通过执行下列语句重新创建新的空表,该语句使用表的描述文件tbl_name.frm 重新开始生成新的数据和索引文件:
  mysql> delete from tbl_name;
  4) 退出mysql,将原始的数据文件移回到数据库目录中,替换刚建立的新的空文件。
  5) 再试试标准表修复方法。
  为了恢复该表的描述文件,可先从备份文件中恢复,然后再试着用标准修复方法。如果由于某些原因没有备份,但知道建立表的create table 语句,则仍可以恢复该文件:
  1) 定位到包含崩溃表的数据库目录中。
  2) 将该表的数据文件移动到安全的地方。如果想要使用索引的话,还需将索引文件移走。
  3) 调用mysql并发布create table 语句建立该表。
  4) 退出mysql,将原始数据文件移回数据库目录中,替换刚才新建的数据文件。如果在步骤2移动了索引文件,则也要将其移回数据库目录中。
  5) 再试试标准表修复方法。

避免与mysql服务器交互作用

  当您正在运行表的检查/修复实用程序时,您或许不想让mysql服务器和实用程序同时访问一个表。如果两个程序都向表中写数据显然是一件坏事,但是,当一个程序在写入时另一个程序在读取也不是件好事。如果表正由一个程序写入,同时进行读取的另一个程序会被
搞乱。
  如果您关闭服务器,就可以保证在服务器和myisamchk 或isamchk 之间没有交互作用。但是管理员极不愿意使服务器完全地脱机,因为这使得没有故障的数据库和表也不可用。本节中讨论的过程将帮助您避免服务器和 myisamchk 或isamchk 之间的交互作用。
  服务器有两种类型的锁定方法。它使用内部锁定避免客户机的请求相互干扰──例如,避免客户机的select 查询被另一个客户机的update查询所干扰。服务器还使用外部锁定(文件级锁)来防止其他程序在服务器使用表时修改该表的文件。通常,在表的检查操作中服务器将外部锁定与myisamchk 或isamchk 组合使用。但是,外部锁定在某些系统中是禁用的,因为它不能可靠地进行工作。对运行myisamchk 和isamchk 所选择的过程取决于服务器是否能使用外部锁定。如果不使用,则必须使用内部锁定协议。
  如果服务器用–skip-locking 选项运行,则外部锁定禁用。该选项在某些系统中是缺省的,如l i n ux。可以通过运行mysqladmin variables 命令确定服务器是否能够使用外部锁定。检查skip_locking 变量的值并按以下方法进行:
  如果skip_locking 为o ff,则外部锁定有效。您可以继续并运行任一个实用程序来检查表。服务器和实用程序将合作对表进行访问。但是,在运行任何一个实用程序之前,应该用 mysqladmin flush-tables 刷新表的高速缓存。为了修复表,应该使用表的修复锁定协议。
  如果skip_locking 为o n,则禁用外部锁定,但在myisamchk 或isamchk 检查或修复一个表时服务器并不知道,最好关闭服务器。如果坚持使服务器保持开启状态,需要确保在您使用此表时没有客户机来访问它。必须使用恰当的锁定协议告诉服务器使该表独处,并阻塞客户机对其访问。
  这里所描述的锁定协议使用服务器的内部锁定机制,以防止服务器在您利用my i s a m c h k或isamchk 工作时访问表。通常的办法是调用mysql并对要检查或修复的表发布l o c k table 语句。然后,在mysql空闲时(即运行,但除了保持该表锁定外不用它做任何事情),运行myisamchk 或i s a m c h k。在myisamchk 或isamchk 结束后,可以切换到mysql会话中并释放该锁以告诉服务器程序执行完毕此表可以再次使用了。
  检查和修复的锁定协议有点区别。对于检查,您只需要获得读锁。在这种情况下,只能读取表,但不能修改它,因此它也允许其他客户机读取它。读锁足以防止其他客户机修改表。对于修复,您必须获得写锁以防止任何客户机在您对表进行操作时修改它。
  锁定协议使用lock table 和unlock table 语句获得并释放锁。协议还使用f l u s h tables 告诉服务器刷新磁盘中任何未决的改变,并在通过表修复实用程序修改表后重新打开该表。您必须从单个mysql会话中执行所有l o c k、flush 和unlock 语句。如果锁定一个表然后退出mysql,则该锁将释放,且运行myisamchk 或isamchk 将不再是安全的!
  如果保持打开两个窗口的状态,且一个运行mysql,而另一个运行myisamchk 或i s a m c h k,则运行锁定过程将会变得很容易。这样允许您很容易地在程序之间进行切换。如果不是运行在视窗环境中,当运行myisamchk 或isamchk 时,将需要使用外壳程序的作业控制工具暂停和恢复mysql。下面的指导显示出对myisamchk 或isamchk 的命令,可用与您正在使用的表相对应的那个命令。
  1. 对检查操作锁定表
  此过程只针对表的检查,不针对表的修复。在窗口1中,调用mysql并发布下列语句:
  % mysqldb_name
  mysql>lock table tbl_name read;
  mysql>flush tables;
  该锁防止其他客户机在检查时写入该表和修改该表。flush 语句导致服务器关闭表的文件,它将刷新仍然在高速缓存中的任何未写入的改变。
  当mysql空闲时,切换到窗口2 并检查该表:
  % myisamchk tbl_name
  % isamchk tbl_name
  当myisamchk 或isamchk 结束时,切换回到窗口1的mysql会话并释放该表锁:
  mysql>unlock table;
  如果myisamchk 或isamchk 指出发现该表的问题,将需要执行表的修复。
  2. 对修复操作锁定表
  修复表的锁定过程类似于检查表的过程,但有两个区别。第一,您必须得到写锁而非读锁。由于您将要修改表,因此根本不允许客户机对其进行访问。第二,必须在执行修复之后发布flush table 语句,因为myisamchk 和isamchk 建立了新的索引文件,除非再次刷新
该表的高速缓存否则服务器将不会注意到它:
  % mysqldb_name
  mysql>lock table tbl_name write;
  mysql>flush tables;
  利用mysql的空闲切换到窗口2,做该表的数据库文件的拷贝,然后运行myisamchk 或i s a m c h k:
  % cp tbl_name.* |some|other|directory
  % myisamchk –recover tbl_name
  % isamchk –recover tbl_name
  –recover 选项只是针对安装而设置的。这些特殊选项的选择将取决于您执行修复的类型。myisamchk 或isamchk 运行完成后,切换回到窗口1的mysql会话,再次刷新该表的高速缓存并释放表锁:
  mysql>flush tables;
  mysql>unlock table;

快速运行myisamchk 和i s a m c h k

  myisamchk 和isamchk 的运行可能会花很长时间,尤其是您正在处理一个大表或使用一个更广泛的检查或修复方法时。通过告诉这些程序在运行时使用更多的内存,能够提高它们的速度。这两个实用程序都有几个可设置的操作参数。其中最重要的是控制程序使用的缓冲
区大小的变量:

变量 含义
key _ buffer _ s i z e 用于存放索引块的缓冲区大小
r e a d _ buffer _ s i z e 读操作用的缓冲区大小
sort _ buffer _ s i z e 排序用的缓冲区大小
w r i t e _ buffer _ s i z e 写操作用的缓冲区大小

  要想查看任一个程序使用的这些变量的缺省值,可用–help 选项运行该程序。要想指定其他的值,可在该命令上使用–set-variable variable=value 或-o variable=value。您可以将变量的名字简化成key、r e a d、sort 和w r i t e。例如,可告诉myisamchk 使用16mb 的排序缓冲区和1mb 的读写缓冲区,其调用如下:
  % myisamchk -0 sort=16m -0 read=1m write=1m …
  sort _ buffer_size 只能利用–recover 选项来使用(而不是利用- – s a f e _ r e c o ver),在这种情况下,key _ buffer 不能使用。
  减少服务器的停机时间
  防止服务器访问(您正在处理的)表的另一种方法是在数据目录的外面使用该表文件的拷贝。这样并不能消除交互作用的问题,因为仍然必须防止服务器访问(并可能修改)正在进行拷贝的表。但是,如果您不愿意使服务器脱机的话,该路线可能是使服务器停机时间最小化的一种方法,这对您是有吸引力的。在将该表的文件拷贝到另一个目录时关闭服务器,然后恢复服务器。
  myisamchk 的未来打算
  myisamchk 的表检查和修复功能打算在mysql3.23 版本系列的某个时候被合并到服务器中。如果这种打算实现,对表的检查和修复将更容易,因为服务器与my i s a m c h k的交互问题将不再会出现。
  同样,您能够告诉服务器在启动时检查表,因此在启动服务器前将不需要设置任何特殊的命令在引导期间执行。该程序不对isam 表进行操作,因此在服务器获得表的检修复能力时,应考虑将isam 表转换成myisam 表。请查看新发行版的mysql参考指南,了解在此范围内有什么新进展。可以用alter table 语句转换表的类型:
  alter table tbl_name type=myisam

退出移动版