UPDATE 时主键冲突引发的思考【转】

假设有一个表,结构如下:


root@localhost : yayun 22:59:43> create table t1 (
-> id int unsigned not null auto_increment,
-> id2 int unsigned not null default ‘0‘,
-> primary key (id)
-> )engine=myisam;
Query OK, 0 rows affected (0.00 sec)

root@localhost : yayun 23:01:00>

改表中有6条记录,如下:


root@localhost : yayun 23:03:35> select * from t1;
+----+-----+
| id | id2 |
+----+-----+
| 2 | 2 |
| 3 | 3 |
| 5 | 5 |
| 4 | 4 |
| 6 | 6 |
| 7 | 7 |
+----+-----+
6 rows in set (0.00 sec)

root@localhost : yayun 23:03:42>

现在想要把id字段分别-1,执行以下语句,得到报错:

root@localhost : yayun 23:03:42> update t1 set id=id - 1;
ERROR 1062 (23000): Duplicate entry ‘4‘ for key ‘PRIMARY‘
root@localhost : yayun 23:04:59>

看看更新后的结果,可以看到:


root@localhost : yayun 23:05:58> select * from t1;
+----+-----+
| id | id2 |
+----+-----+
| 1 | 2 |
| 2 | 3 |
| 5 | 5 |
| 4 | 4 |
| 6 | 6 |
| 7 | 7 |
+----+-----+
6 rows in set (0.00 sec)

root@localhost : yayun 23:06:05>

存储在最前面的2条记录更新成功了,后面的则失败,因为第三条记录如果也要更新,则会引发主键冲突。
这个时候,如果我们在更新时增加 ORDER BY
的话,则可以顺利更新成功。

root@localhost : yayun 23:07:52> update t1 set id=id-1 order by id;
Query OK, 6 rows affected (0.00 sec)
Rows matched: 6 Changed: 6 Warnings: 0

root@localhost : yayun 23:08:20>

接下来,我们看看把它转成 innodb 表,结果会是怎样的。

root@localhost : yayun 23:09:21> alter table t1 engine = innodb;
Query OK, 6 rows affected (0.08 sec)
Records: 6 Duplicates: 0 Warnings: 0

root@localhost : yayun 23:09:23>


root@localhost : yayun 23:10:15> select * from t1;
+----+-----+
| id | id2 |
+----+-----+
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
+----+-----+
6 rows in set (0.00 sec)

root@localhost : yayun 23:10:19>

看到变化了吧,行数据按照 id 的顺序来显示了。清空后,自己重新手工插入记录,再看看。


root@localhost : yayun 23:11:05> delete from t1;
Query OK, 6 rows affected (0.00 sec)

root@localhost : yayun 23:11:28> INSERT INTO `t1` VALUES (2,2),(3,3),(5,5),(4,4),(6,6),(7,7);
Query OK, 6 rows affected (0.09 sec)
Records: 6 Duplicates: 0 Warnings: 0

root@localhost : yayun 23:11:33>

还是按照 id 的顺序来显示,然后我们再次执行之前的 update 语句:

root@localhost : yayun 23:12:03> update t1 set id = id - 1;
Query OK, 6 rows affected (0.03 sec)
Rows matched: 6 Changed: 6 Warnings: 0

root@localhost : yayun 23:12:29>

可以看到,在 innodb 表的情况下,更新是可以成功的。

总结:

myisam表是堆组织表(Heap
Organize Table, HOT),它的索引是采用 b-tree
方式存储的,数据显示时是随机顺序,而非按照主键的索引顺序来显示。
而innodb表是索引组织表(Index Organized Table,
IOT),它的索引则是采用 clustered index 方式,因此主键会按照顺序存储,每次有记录有更新时,会重新整理更新其主键。因此无论是直接从
myisam 表转换过来的,还是后来插入的记录,显示时都会按照主键的顺序。
更新数据时,如果没有指定排序的字段或索引,则默认以随机顺序更新,所以
myisam 表如果不指定 ORDER BY 的话,则采用默认的存储顺序来更新,所以会发生主键冲突的情况。
而 innodb
表总是有主键(如果没有定义,则也有默认主键),如果更新时没有指定排序字段或索引,则按照主键顺序来更新,在上面的例子中,就是按照主键 id
的顺序来更新了,因此不会报错。

原文地址

http://imysql.com/2008_06_17_sth_about_update_duplicate_key

UPDATE 时主键冲突引发的思考【转】,布布扣,bubuko.com

时间: 2024-10-17 18:56:10

UPDATE 时主键冲突引发的思考【转】的相关文章

insert时出现主键冲突的处理方法

使用"insert into"语句进行数据库操作时可能遇到主键冲突,用户需要根据应用场景进行忽略或者覆盖等操作.总结下,有三种解决方案来避免出错. 测试表:CREATE TABLE `device` (`devid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,`status` enum('alive','dead','down','readonly','drain') DEFAULT NULL,`spec_char` varchar(1

[转]主键冲突的话就更新否则插入 (ON DUPLICATE KEY UPDATE )

mysql "ON DUPLICATE KEY UPDATE" 语法如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则在出现重复值的行执行UPDATE:如果不会导致唯一值列重复的问题,则插入新行. 例如,如果列 a 为 主键 或 拥有UNIQUE索引,并且包含值1,则以下两个语句具有相同的效果: INSERT INTO TABLE (a,c) VALUES (1,3) ON D

django使用postgresql时提示主键冲突

在django使用postgresql数据库时,当你使用默认主键,但当你手动使用添加记录到相关数据库时(非insert操作,如使用navicate直接在表中复制粘贴记录),此时django在插入数据时,会提示主键冲突,这是因为postgresql的主键自增是建立在它内部机制工作的,你可以使用如下sql来获取或设置相关的自增ID序列: select nextval('表名_id_seq'); #此操作会获取当前基于表中最大ID,并会设置ID+1 select currval('表名_id_seq'

多线程调用生成主键流水号存储过程产生主键冲突问题解决方案

遇到开发多线程测试插入数据的时候发现主键冲突问题 问题具体描述如下: -------------------------------------------------------------- 调用Procedure_insert Procedure_insert Begin Call procedure(获取流水号) Insert into table values(流水号作为id,其他列); End 流水号存储过程: Update 统计表 统计字段+1 Update 统计表 最终流水号 s

mysql修改数据 -- 主键冲突

mysql 插入数据唯一键冲突 前提: 修改数据三种可用的方法解决主键冲突的问题 1. insert into ... on duplicate key update set ... 2. update ... set = case key when ... then ... when ... then ... else end where ...; 3. replace into ... (与1相似,但若主键冲突会先删除原数据,后再插入新数据 ,所以运用时最好带上主键) 例: table :

MySQL 复制 主键冲突

看了下复制的问题,最明显的一个案例就是主键冲突,今天就看下这个问题 什么原因会导致这个问题 怎么规避这个问题 一.什么原因导致 网上最多的说就是:对于存在auto_increment字段或者unique索引字段,使用replace into操作或者主从切换,因为replace into对于auto或者unique字段会进行删除再做插入 执行replace into t values(1,2)被删除和被插入的行数的和(大于或者等于1) master 上 SHOW CREATE TABLE `tes

图片的批量导入实现和对主键生成策略的思考

CDX一期上线的那天是我来公司最紧张的一天,因为这一天我要负责公司近5000张车型图的导入工作.虽然在完成上传和导入的代码之后测试了很多遍,但是真正到了正式环境,却真的很怕出问题.内搜.gift.以及本地和线上数据库的同步,哪一个环节出了问题都会影响上线的时间.现在一期上了线,也对自己图片上传导入这部分做一些总结,还有对现有方法不足之处的一些思考. 其实一张图的上传逻辑还是比较简单的: 1. 上传图片到gift服务器. 2. 保存图片信息到线上数据库. 3. 将图片信息按固定格式推送给内搜,便于

sql解决主键冲突

在数据插入的时候,假设主键对应的值已经存在,则插入失败!这就是主键冲突.当主键存在冲突(duplicate key)的时候,可以选择性的进行处理,即忽略.更新或者替换. 1.忽略 insert ignore into table 保持原记录,忽略新插入的记录 2.替换 replace into table 替换原记录,即先删除原记录,再插入新的记录 3. 更新 insert into table value("xx","xx") ON DUPLICATE KEY U

13.MySQL解决主键冲突

1.准备 1 CREATE DATABASE mahaiwuji; 2 USE mahaiwuji; 3 ? 4 CREATE TABLE emp 5 ( 6 empno INT PRIMARY KEY, 7 ename VARCHAR(10), 8 sal INT 9 ) ENGINE = INNODB DEFAULT CHARSET = utf8; 10 ? 11 INSERT INTO emp VALUES (1,'smith',2800); 12 INSERT INTO emp VALU