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

root@localhost : yayun 22:59:43> create table t1 (
-> id int unsigned not null auto_increment,
-> id2 int unsigned not null default '',
-> 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 '' 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 时主键冲突引发的思考【转】的更多相关文章

  1. Entity Framework中Remove、Modified实体时,在修改或删除时引发主键冲突的问题

    问题: try { string fileId = context.NewsT.Where(t => t.Id == Model.Id).FirstOrDefault().FileId; str ...

  2. insert时出现主键冲突的处理方法【转载】

    原文出处:http://hi.baidu.com/ytjwt/blog/item/1ccc2c26022b0608908f9d8c.html 使用"insert into"语句进行 ...

  3. sqoop从hive导入数据到mysql时出现主键冲突

    今天在将一个hive数仓表导出到mysql数据库时出现进度条一直维持在95%一段时间后提示失败的情况,搞了好久才解决.使用的环境是HUE中的Oozie的workflow任何调用sqoop命令,该死的o ...

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

    使用"insert into"语句进行数据库操作时可能遇到主键冲突,用户需要根据应用场景进行忽略或者覆盖等操作.总结下,有三种解决方案来避免出错. 测试表:CREATE TABLE ...

  5. mysql 主从,主主,主主复制时的主键冲突解决

    原理:slave 的i/o thread ,不断的去master抓取 bin_log, 写入到本地relay_log 然后sql thread不断的更新slave的数据 把主服务器所有的数据复制给从服 ...

  6. mysql修改数据 -- 主键冲突

    mysql 插入数据唯一键冲突 前提: 修改数据三种可用的方法解决主键冲突的问题 1. insert into ... on duplicate key update set ... 2. updat ...

  7. sqlite里执行查询提示未启用约束、主键冲突之——数据竟能超字段长度存储

    数据表设计如图:szflbm为主键 数据表主键数据: 以上数据在查询时,执行到该语句adapter.Fill(table); 提示主键冲突. 解决: 1.尝试修改数据,把ZC1改成ZZ,正常.说明原因 ...

  8. MySql中利用insert into select 准备数据uuid主键冲突

    MYSQL 中表1需要准备大量数据,内容主要取自表2,id必须为32位uuid (项目所有表都是这样,没办法), 准备这样插入: INSERT INTO TBL_ONE (ID, SOID, SNAM ...

  9. sql解决主键冲突

    在数据插入的时候,假设主键对应的值已经存在,则插入失败!这就是主键冲突.当主键存在冲突(duplicate key)的时候,可以选择性的进行处理,即忽略.更新或者替换. 1.忽略 insert ign ...

随机推荐

  1. [UI] 06 - jQuery

    前言 From : http://www.runoob.com/jquery/jquery-intro.html Ref: jQuery 实例 一.什么是 jQuery ? jQuery是一个Java ...

  2. 【代码审计】OTCMS_PHP_V2.83_代码执行漏洞分析

      0x00 环境准备 OTCMS官网:http://otcms.com 网站源码版本:网钛CMS PHP版 V2.83 [更新于2017.12.31] 程序源码下载:http://d.otcms.c ...

  3. OSG描边特效osgFX::Outline的修改

    对一个三维场景中的物体实现描边特效,可以参考osg范例osgoutline 这个描边特效使用了模板缓存Stencil来实现,参见源代码osgFX/Outline.cpp 使用了两个Pass 第一个Pa ...

  4. redis如何后台启动

    当安装好redis之后,运行redis-server命令之后,显示如图所示: 但是这样没有办法在这个tab下做任何操作了,因为这个时候使用Ctrl+c之后,就变成了这个样子 然后就关闭了,那么我想让r ...

  5. Java Debugging with Eclipse - Tutorial

    1.1. What is debugging? Debugging allows you to run a program interactively while watching the sourc ...

  6. 《Thinkphp5使用Socket服务》 入门篇

    上车啦!!! 今天来说一下thinkphp5.0下使用wokerman的socket服务. 安装: composer的安装方法,Windows下直接下个composer的应用程序,双击安装,环境变量同 ...

  7. Mongodb----整理

    ----------------------------------------------------------------------------------mongodb基本操作------- ...

  8. nvidia-smi failed because it couldn't communicate with the nvidia driver

    Ubuntu装好CUDA之后过段时间提示NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. NV ...

  9. vim与程序员 vi/vim 的使用

    vim与程序员   所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在. 但是目前我们使用比较多的是 vim 编辑器. vim 具有程序编辑的能力,可以主动的以 ...

  10. java虚拟机学习

    //20181129 ·Java虚拟机的内存分为三个部分:栈stack.堆heap.方法区method area----包含在“堆”里面,因为作用特殊所以单独列出来 ·栈的特点:     栈描述的是方 ...