Chinaunix

标题: MyISAM表插入数据的经常Duplicate entry key的问题 [打印本页]

作者: 乱.码    时间: 2008-04-17 14:52
标题: MyISAM表插入数据的经常Duplicate entry key的问题
MyISAM表结构,发现如果程序经常的insert数据,时间长了后就会出现Duplicate entry ‘xxx’ for key... 的问题,repair表后就回复正常了,ID是autoincrement的,也没有重复的键值,只有一个程序对其进行insert操作,不知道是不是Myisam引擎本身的问题呢?
这种问题是没有规律的,不一定什么时候就出现了,不过一般是数据量比较大的时候,比如达到6位数出现的几率就多了一点。
作者: chouy    时间: 2008-04-17 15:17
原帖由 乱.码 于 2008-4-17 14:52 发表
MyISAM表结构,发现如果程序经常的insert数据,时间长了后就会出现Duplicate entry ‘xxx’ for key... 的问题,repair表后就回复正常了,ID是autoincrement的,也没有重复的键值,只有一个程序对其进行insert操 ...


我这里也出现了同样的问题:
一个表主键是 auto_increment 的 int, 测试发现这个表的数据很长时间没有更新, 查看发现:
max(id)  是 126, 然后 insert 一条数据报 duplicate key of '127', 但在 select * 表时并没有 ID 为 127 这条数据.
重启 mysql 服务, 问题依旧. 插入一条 id = 150 的数据成功, 但 mysql 自己还是不能增加数据, 继续报错.
于是 mysqlcheck 了一个这个表, 问题解决.
我知道 myisam 这种存储引挚是有些问题, 经常会出错, 但我想问问这种问题出现的几率, mysqlcheck 是否可以百分百修复这个问题.


求高人指教.
作者: yueliangdao0608    时间: 2008-04-17 15:46
坛子上讨论很多了。
设置
auto_increment_increment

auto_increment_offset

的值。
作者: 乱.码    时间: 2008-04-17 16:00
原帖由 yueliangdao0608 于 2008-4-17 15:46 发表
坛子上讨论很多了。
设置
auto_increment_increment

auto_increment_offset

的值。


我这只有一个mysql服务器 不存在服务器的复制、同步等问题 设这有用嘛
作者: yueliangdao0608    时间: 2008-04-17 16:01
RESET MASETER
重新设置一下你的SLAVE
作者: 乱.码    时间: 2008-04-17 16:09
原帖由 yueliangdao0608 于 2008-4-17 16:01 发表
RESET MASETER
重新设置一下你的SLAVE


我这只有一个mysql服务器 也就是一个数据库 不存在主从的问题
作者: yueliangdao0608    时间: 2008-04-17 16:24
不好意思,没有看清楚。
贴你的表结构看看。
还有你的版本
作者: 乱.码    时间: 2008-04-17 16:40
标题: 回复 #7 yueliangdao0608 的帖子

  1. mysql> desc Syslog;
  2. +-------+--------------+------+-----+-------------------+----------------+
  3. | Field | Type         | Null | Key | Default           | Extra          |
  4. +-------+--------------+------+-----+-------------------+----------------+
  5. | id    | int(11)      |      | PRI | NULL              | auto_increment |
  6. | fac   | tinyint(4)   |      | MUL | 0                 |                |
  7. | pri   | tinyint(4)   |      | MUL | 0                 |                |
  8. | host  | varchar(64)  | YES  |     | NULL              |                |
  9. | time  | timestamp    | YES  | MUL | CURRENT_TIMESTAMP |                |
  10. | msg   | varchar(255) | YES  |     | NULL              |                |
  11. +-------+--------------+------+-----+-------------------+----------------+
复制代码


5.0.18
作者: chouy    时间: 2008-04-17 17:36
我的建库语句:
  1. CREATE TABLE `sys_log` (
  2.   `log_id` int(11) NOT NULL AUTO_INCREMENT,
  3.   `log_type` enum('1','2','3','4') NOT NULL DEFAULT '1',
  4.   `log_level` enum('1','2','3') NOT NULL DEFAULT '1',
  5.   `log_time` varchar(14) NOT NULL DEFAULT '',
  6.   `log_content` text NOT NULL,
  7.   `report_flag` enum('0','1') NOT NULL DEFAULT '0',
  8.   PRIMARY KEY (`log_id`)
  9. ) ENGINE=MyISAM AUTO_INCREMENT=26832 DEFAULT CHARSET=latin1
复制代码

数据库版本:
5.0.21-community

我的数据库也是只有一个库, 没有主从和同步关系.

[ 本帖最后由 chouy 于 2008-4-17 17:38 编辑 ]
作者: 猪知猪之道    时间: 2008-04-17 17:36
原帖由 乱.码 于 2008-4-17 16:40 发表

mysql> desc Syslog;
+-------+--------------+------+-----+-------------------+----------------+
| Field | Type         | Null | Key | Default           | Extra          |
+-------+----------- ...



show create table Syslog  出来看看
作者: 乱.码    时间: 2008-04-17 17:41
show create table Syslog;

| Syslog | CREATE TABLE `Syslog` (
  `id` int(11) NOT NULL auto_increment,
  `fac` tinyint(4) NOT NULL default '0',
  `pri` tinyint(4) NOT NULL default '0',
  `host` varchar(64) default NULL,
  `time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  `msg` varchar(255) default NULL,
  PRIMARY KEY  (`id`),
  KEY `priSyslog` (`pri`),
  KEY `facSyslog` (`fac`),
  KEY `timeSyslog` (`time`),
  FULLTEXT KEY `msg` (`msg`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |

后面3个KEY因为在上面建立了索引常用于查询 正考虑给删了 否则应该会影响插入效率吧 但不至于是问题所在吧
作者: 猪知猪之道    时间: 2008-04-17 17:47
下次出这样的问题建议你
analyze table Syslog; 看表到底有错误没
select MAX(id) from Syslog;  检查ID
show create table Syslog;
看 ) ENGINE=MyISAM AUTO_INCREMENT=1028 DEFAULT CHARSET=latin1 |   表最后的这个ID
作者: 乱.码    时间: 2008-04-18 10:33
原帖由 猪知猪之道 于 2008-4-17 17:47 发表
下次出这样的问题建议你
analyze table Syslog; 看表到底有错误没
select MAX(id) from Syslog;  检查ID
show create table Syslog;
看 ) ENGINE=MyISAM AUTO_INCREMENT=1028 DEFAULT CHARSET=latin1 |   ...


出问题的时候我用了check 列出了类似这样的错误:
error | Found xxxx keys of yyyy
error | corrupt

其中xxxx != yyyy
select max(id) from Syslog;
返回的值也不等于 最后一条记录的ID
作者: cocolala    时间: 2008-04-24 00:01
看来这个问题确实比较古怪,mysqlcheck 能解决它,不知道它做了什么事?
看了手册,只知道如果auto_increment列值达到了列的类型的最大值,那么下一次insert时,因为超出范围,mysql会用最大值赋值给auto increment计数器及列值,这时会与前面已经存在的记录冲突,报'duplicate key'

参见http://blog.chinaunix.net/u2/67276/showart_574312.html

int类型最大值上了10位数了,楼主是6位数时就出错,奇怪了!
作者: yueliangdao0608    时间: 2008-04-24 09:12
原帖由 cocolala 于 2008-4-24 00:01 发表
看来这个问题确实比较古怪,mysqlcheck 能解决它,不知道它做了什么事?
看了手册,只知道如果auto_increment列值达到了列的类型的最大值,那么下一次insert时,因为超出范围,mysql会用最大值赋值给auto in ...


有符号的11位,无符号的10位。
这个的确有点可能,不过单表的记录超过亿了。我觉得是不是应该分一下表了。
作者: cocolala    时间: 2008-04-24 11:26
原帖由 乱.码 于 2008-4-18 10:33 发表


出问题的时候我用了check 列出了类似这样的错误:
error | Found xxxx keys of yyyy
error | corrupt

其中xxxx != yyyy
select max(id) from Syslog;
返回的值也不等于 最后一条记录的ID



看你mysqlcheck的结果,可知应该是因为mysql表损坏导致这种情况.
当指定插入127这个值时,mysql发现key中已经存在(可能是因为之前在insert时,刚好在127这个地方出问题了,更新key文件ok,但更新数据文件失败).根据约束规则,所以报duplicate key错误;
作者: yueliangdao0608    时间: 2008-04-24 12:39
最直接的办法就是导出所有数据,然后导入
作者: 乱.码    时间: 2008-04-25 09:26
这个问题我实在没搞清楚为什么会出现,也不明白为什么会无缘无故出现表损坏的情况,难道myisam经常出现这个问题?不清楚。
因为我并非手动插入数据,而是有个C程序持续的往里写数据,并且是单进程、单线程的,绝对不会同时有两个session往里写数据,id字段,int类型,也就是auto_increment字段也是不指定的,让其自动增长,可就是当数据量达到6位数时就会出现这个问题,执行表修复就正常了,之后偶尔也会出现。
作者: yueliangdao0608    时间: 2008-04-25 09:53
原帖由 乱.码 于 2008-4-25 09:26 发表
这个问题我实在没搞清楚为什么会出现,也不明白为什么会无缘无故出现表损坏的情况,难道myisam经常出现这个问题?不清楚。
因为我并非手动插入数据,而是有个C程序持续的往里写数据,并且是单进程、单线程的, ...



六位数?

你确定你的自增字段类型不是MEDIUMINT的?
作者: 乱.码    时间: 2008-04-25 10:22
原帖由 yueliangdao0608 于 2008-4-25 09:53 发表



六位数?

你确定你的自增字段类型不是MEDIUMINT的?

不是 定义的int 系统识别的应该是int(11)

不是一到6位数就OVER了 比如有时是123456条记录OVER 有时是654321条记录OVER 我说的意思就是说在6位数时候比较常见
作者: sunnyfun    时间: 2008-04-25 12:51
可能连续写表写得太狠了吧,可以试试这样:
锁表→写个几百条→解锁→歇一会
如此循环。
作者: yueliangdao0608    时间: 2008-04-25 13:11
如果写太多的话,还是建议换成INNODB引擎。
作者: 乱.码    时间: 2008-04-25 13:44
嗯,因为是应用程序的日志表,所以写会频繁些,偶尔会查询,不会很多,我也觉得应该改成INNODB引擎。

谢谢各位的回复
作者: huifeideluotuo    时间: 2008-04-26 17:06
如果你是关键应用,机器性能不是很好(不经常死机)的情况下,我也推荐你用INNODB引擎,因为MYISAM引擎,在非法关闭mysql的时候,出现表损坏,虽然可以修复,但是以后还会出现,如果你对mysql性能不是特别苛刻,建议你用mysql官方提供的已经编译好的二进制版本。:wink:




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2