为什么 MySQL 表会崩溃?我该如何预防?

Aer*_*oss 9 mysql myisam

我是Moodle站点的管理员,该站点的用户表已损坏并且无法使用。

幸运的是,一个简单的方法REPAIR TABLE mdl_user使它再次工作。问题是我不知道为什么它实际上崩溃并使其无法使用,我想确保下次我有更好的准备。

我不是一个经验丰富的 DBA——我只是一个做很多事情的开发人员,所以请耐心等待。

我可以只恢复备份,但我想有办法防止崩溃。

这些表是 utf8_general_ci 并使用 MyISAM。

为什么 MySQL 表会崩溃?我能做些什么来防止这种情况发生?

Rol*_*DBA 11

MyISAM 表很容易崩溃。

在每个 MyISAM 表的标头中都有一个计数器,用于跟踪表中有多少打开的文件句柄。

如果您启动 mysql 并且标头中的数字与实际文件句柄的数量不匹配,mysqld 会将表视为崩溃。

如果一个简单的方法REPAIR TABLE mdl_user每次都能再次运行而不会丢失数据,这可能表明您有一个访问量非常大的站点,该站点写入mdl_user.

如果有几十个表需要这个REPAIR TABLE,我会将所有表转换为 InnoDB。但是,如果该mdl_user表是唯一存在此问题的表,则您可以执行某些操作(在此示例中,假设数据库为moodle);

如果您希望所有表都保留为 MyISAM

步骤 01:创建修复表脚本

echo "REPAIR TABLE moodle.mdl_user;" > /var/lib/mysql/MoodleStartUp.sql
Run Code Online (Sandbox Code Playgroud)

STEP 02 : 将修复脚本声明为启动文件

将此添加到 /etc/my.cnf

[mysqld]
init-file=/var/lib/mysql/MoodleStartUp.sql
Run Code Online (Sandbox Code Playgroud)

步骤 03:重启 mysql

每次重启mysql都会触发Repair Table Script

如果你想让所有的表都变成 InnoDB

运行此代码制作MyISAM表到InnoDB的批量转换脚本,查看

MYSQL_USER=root
MYSQL_PASS=password
MYSQL_CONN="-u${MYSQL_USER} -p ${MYSQL_PASS}"
echo "SET SQL_LOG_BIN = 0;" > /root/ConvertMyISAMToInnoDB.sql
mysql ${MYSQL_CONN} -A --skip-column-names -e"SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' ENGINE=InnoDB;') InnoDBConversionSQL FROM information_schema.tables WHERE engine='MyISAM' AND table_schema NOT IN ('information_schema','mysql','performance_schema') ORDER BY (data_length+index_length)" > /root/ConvertMyISAMToInnoDB.sql
less /root/ConvertMyISAMToInnoDB.sql
Run Code Online (Sandbox Code Playgroud)

一旦您对转换脚本的内容感到满意,然后运行它

mysql ${MYSQL_CONN} < /root/ConvertMyISAMToInnoDB.sql
Run Code Online (Sandbox Code Playgroud)

更新 2012-03-15 14:00 EDT

@Kevin,在使用 MyISAM 时,如果磁盘空间不足是您的问题怎么办?

这里需要考虑:根据MySQL 5.0 Certification Study Guide

在此处输入图片说明

第 11页第 408,409 页第 29.2 节中的要点如下:

如果在向 MyISAM 表添加行时磁盘空间不足,则不会发生错误。服务器暂停操作,直到空间可用,然后完成操作。

当磁盘空间不足时,不要只是关闭或杀死 mysql。任何当前使用的 MyISAM 中打开文件句柄的计数将不会被清除。因此,MyISAM 表被标记为崩溃。如果您可以在 mysqld 仍在运行的情况下释放数据卷中的磁盘空间,一旦磁盘空间可用,mysqld 将继续使用。