一点关于MySQL参数delay_key_write、myisam_recover_options的使用经验(一)

2014-11-24 14:38:42 · 作者: · 浏览: 2
一点关于MySQL参数delay_key_write、myisam_recover_options的使用经验
最近在做 数据库实例迁移的时候遇到了几个比较诡异的问题:
MyISAM实例正常shutdown后rsync数据文件到另外一台机器上起实例后,访问表时提示表自动修复失败需要repair table。提示信息:Table './test/record_03' is marked as crashed and last (automatic ) repair failed
表损坏后,利用repair table命令将表修复时提示表里存在很多的duplicate key.
warning : Duplicate key for record at 129584986 against record at 62008769
warning : Duplicate key for record at 104678355 against record at 61426294
warning : Duplicate key for record at 297493788 against record at 61697778
warning : Duplicate key for record at 209950328 against record at 61548867
warning : Duplicate key for record at 105894968 against record at 61866949
...
...
补充一下当时的环境信息:
1.MySQL版本为官方版的5.5.12,表引擎是MyISAM
2.迁移的步骤:stop slave->flush tables->正常shutdown实例->rsync表文件->在新机器上起实例。rsync前后表文件 MD5值一样。
3.表的结构类似这样:
[sql]
create table test (
id int auto_increment primary key,
a varchar(100) not null,
b int not null,
c int,
unique key (a,b)
)
首先说第一个问题,这里分两点:1.为什么会需要修复?2.为什么自动修复失败?
我是正常关闭实例,不明白表需要修复的原因于是请淘宝丁奇帮忙分析了数据文件,显示文件头里记录显示表被关闭仍有6个线程在访问。但我可以确定当时rsync数据文件前是正常shutdown实例的,这个可能是MyISAM本身的问题或者是本身数据文件就已经存在问题都不得而知,总而言之当我迁移过来后访问表时需要修复这点是合理的,因为表被关闭时还有线程在访问,这会被MySQL认为表非正常关闭,需要修复。
为什么会自动修复失败,这是由于我配置了参数myisam_recover_options=default,这个配置表示每次访问MyISAM表之前都会先检测表是否需要修复,如果需要则自动进行,这也就是前面看到信息last (automatic ) repair failed。而修复失败是因为这个参数带来的修复行为默认是从key cache里面找需要修复的数据,而我当时是shutdown实例,rsync到新环境中起实例,此时已没有当时的现场(key cache环境),加上default不会强制进行修复(强制修复表如果索引文件和数据文件数据不一致则自动进行删除或者增加行),(如果是myisam_recover_options=force,那么即使此时key cache不存在了也会进行强制修复,此时做的就是对比数据文件和索引文件,然后删除数据文件中多余的行,因此这样可能会丢数据)。在自动修复时可以再error log中看到如下信息:
130410 9:31:23 [ERROR] /usr/local/ mysql55/bin/mysqld: Table './image_0/record_00' is marked as crashed and should be repaired
130410 9:31:23 [Warning] Checking table: './image_0/record_00'
130410 9:31:24 [ERROR] Got an error from unknown thread, /export/home/pb2/build/sb_0-3198286-1302530066.93/mysql-5.5.12/storage/myisam/ha_myisam.cc:868
130410 9:31:24 [Warning] Recovering table: './image_0/record_00'
130410 9:31:28 [Note] Retrying repair of: './image_0/record_00' with keycache
130410 9:31:37 [ERROR] Couldn't repair table: image_0.record_00
接着说第二个问题,在第一个问题中提示表损坏,需要手工repair table,而我执行了这条命令后提示表里存在很多重复键数据:
warning : Duplicate key for record at 129584986 against record at 62008769
warning : Duplicate key for record at 104678355 against record at 61426294
warning : Duplicate key for record at 297493788 against record at 61697778
warning : Duplicate key for record at 209950328 against record at 61548867
warning : Duplicate key for record at 105894968 against record at 61866949
这个重复键指的是唯一键(a,b),然后进行了一个小测试验证是数据文件里面有重复的行(在a,b字段上)。逻辑图大概是这样
[plain]
id a b c
1 1 2 3
2 1 2 4
3 2 3 55
4 2 3 54
上面这个列表是我自己模拟的,在(a,b)上有唯一键约束,但是在数据文件中却存在(a,b)重复的行。验证方法较简单:
/*强制走全表扫描*/select * from test where a=val1 and b=val2;
结果集有2行
/*强制走索引*/select * from test where a=val1 and b=val2;
结果集只有1行
当时遇到问题第一反应是开发人员那边是不是曾经导过数据且导数据的时候禁止了唯一约束检查,但是事实上开发说自己没这么干过,于是开发说这是MySQL的bug,我怎么也觉得MySQL不会存在这样大的bug,一直觉得是对MySQL使用方法不对。于是对迁移前后的环境做了对比检查终于发现了疑点:老的环境中配置了dela