自增ID出现Duplicate entry ‘xxx’ for key


http://www.chinaunix.net 作者:乱.码   发表于:2008-04-26 17:06:23 【发表评论】【查看原文】【MySQL讨论区】【关闭
MyISAM表结构,发现如果程序经常的insert数据,时间长了后就会出现Duplicate entry ‘xxx’ for key… 的问题,repair表后就回复正常了,ID是autoincrement的,也没有重复的键值,只有一个程序对其进行insert操作,不知道是不是Myisam引擎本身的问题呢?
这种问题是没有规律的,不一定什么时候就出现了,不过一般是数据量比较大的时候,比如达到6位数出现的几率就多了一点。


chouy 回复于:2008-04-17 15:17:29

引用:原帖由 乱.码 于 2008-4-17 14:52 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8232262&ptid=1081926]
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:14

坛子上讨论很多了。
设置
auto_increment_increment

auto_increment_offset

的值。


乱.码 回复于:2008-04-17 16:00:16

引用:原帖由 yueliangdao0608 于 2008-4-17 15:46 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8232713&ptid=1081926]
坛子上讨论很多了。
设置
auto_increment_increment

auto_increment_offset

的值。

我这只有一个mysql服务器 不存在服务器的复制、同步等问题 设这有用嘛


yueliangdao0608 回复于:2008-04-17 16:01:19

RESET MASETER
重新设置一下你的SLAVE


乱.码 回复于:2008-04-17 16:09:24

引用:原帖由 yueliangdao0608 于 2008-4-17 16:01 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8232896&ptid=1081926]
RESET MASETER
重新设置一下你的SLAVE

我这只有一个mysql服务器 也就是一个数据库 不存在主从的问题:em14:


yueliangdao0608 回复于:2008-04-17 16:24:27

不好意思,没有看清楚。
贴你的表结构看看。
还有你的版本


乱.码 回复于:2008-04-17 16:40:58

mysql> desc Syslog;
+——-+————–+——+—–+——————-+—————-+
| Field | Type          | Null | Key | Default            | Extra           |
+——-+————–+——+—–+——————-+—————-+
| id     | int(11)       |       | PRI | NULL               | auto_increment |
| fac    | tinyint(4)    |       | MUL | 0                  |                 |
| pri    | tinyint(4)    |       | MUL | 0                  |                 |
| host   | varchar(64)   | YES   |      | NULL               |                 |
| time   | timestamp     | YES   | MUL | CURRENT_TIMESTAMP |                 |
| msg    | varchar(255) | YES   |      | NULL               |                 |
+——-+————–+——+—–+——————-+—————-+

5.0.18


chouy 回复于:2008-04-17 17:36:32

我的建库语句:
CREATE TABLE `sys_log` (
   `log_id` int(11) NOT NULL AUTO_INCREMENT,
   `log_type` enum(‘1′,’2′,’3′,’4’) NOT NULL DEFAULT ‘1’,
   `log_level` enum(‘1′,’2′,’3’) NOT NULL DEFAULT ‘1’,
   `log_time` varchar(14) NOT NULL DEFAULT ”,
   `log_content` text NOT NULL,
   `report_flag` enum(‘0′,’1’) NOT NULL DEFAULT ‘0’,
   PRIMARY KEY (`log_id`)
) ENGINE=MyISAM AUTO_INCREMENT=26832 DEFAULT CHARSET=latin1
数据库版本:
5.0.21-community

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

[ 本帖最后由 chouy 于 2008-4-17 17:38 编辑 ]


猪知猪之道 回复于:2008-04-17 17:36:39

引用:原帖由 乱.码 于 2008-4-17 16:40 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8233381&ptid=1081926]

mysql> desc Syslog;
+——-+————–+——+—–+——————-+—————-+
| Field | Type          | Null | Key | Default            | Extra           |
+——-+———– …

show create table Syslog   出来看看


乱.码 回复于:2008-04-17 17:41:27

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:17

下次出这样的问题建议你
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:35

引用:原帖由 猪知猪之道 于 2008-4-17 17:47 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8234271&ptid=1081926]
下次出这样的问题建议你
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: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:09

引用:原帖由 cocolala 于 2008-4-24 00:01 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8268513&ptid=1081926]
看来这个问题确实比较古怪,mysqlcheck 能解决它,不知道它做了什么事? 🙂
看了手册,只知道如果auto_increment列值达到了列的类型的最大值,那么下一次insert时,因为超出范围,mysql会用最大值赋值给auto in …

有符号的11位,无符号的10位。
这个的确有点可能,不过单表的记录超过亿了。我觉得是不是应该分一下表了。


cocolala 回复于:2008-04-24 11:26:09

引用:原帖由 乱.码 于 2008-4-18 10:33 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8237154&ptid=1081926]

出问题的时候我用了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:15

最直接的办法就是导出所有数据,然后导入


乱.码 回复于:2008-04-25 09:26:46

这个问题我实在没搞清楚为什么会出现,也不明白为什么会无缘无故出现表损坏的情况,难道myisam经常出现这个问题?不清楚。
因为我并非手动插入数据,而是有个C程序持续的往里写数据,并且是单进程、单线程的,绝对不会同时有两个session往里写数据,id字段,int类型,也就是auto_increment字段也是不指定的,让其自动增长,可就是当数据量达到6位数时就会出现这个问题,执行表修复就正常了,之后偶尔也会出现。


yueliangdao0608 回复于:2008-04-25 09:53:40

引用:原帖由 乱.码 于 2008-4-25 09:26 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8276246&ptid=1081926]
这个问题我实在没搞清楚为什么会出现,也不明白为什么会无缘无故出现表损坏的情况,难道myisam经常出现这个问题?不清楚。
因为我并非手动插入数据,而是有个C程序持续的往里写数据,并且是单进程、单线程的, …

六位数?

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


乱.码 回复于:2008-04-25 10:22:55

引用:原帖由 yueliangdao0608 于 2008-4-25 09:53 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=8276460&ptid=1081926]

六位数?

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

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

不是一到6位数就OVER了 比如有时是123456条记录OVER 有时是654321条记录OVER 我说的意思就是说在6位数时候比较常见:mrgreen:


sunnyfun 回复于:2008-04-25 12:51:12

可能连续写表写得太狠了吧,可以试试这样:
锁表→写个几百条→解锁→歇一会
如此循环。


yueliangdao0608 回复于:2008-04-25 13:11:03

如果写太多的话,还是建议换成INNODB引擎。


乱.码 回复于:2008-04-25 13:44:54

嗯,因为是应用程序的日志表,所以写会频繁些,偶尔会查询,不会很多,我也觉得应该改成INNODB引擎。

谢谢各位的回复:)


huifeideluotuo 回复于:2008-04-26 17:06:23

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