`
fantaxy025025
  • 浏览: 1328881 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

Mysql_inserOrUpdate_解决方法和存在问题_insert into on duplicate key update

 
阅读更多

 

解决问题:Mysql_inserOrUpdate_解决方法

http://www.jb51.net/article/39255.htm

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 DUPLICATE KEY UPDATE c=c+1;
UPDATE TABLE SET c=c+1 WHERE a=1;


如果行作为新记录被插入,则受影响行的值显示1;如果原有的记录被更新,则受影响行的值显示2。 
这个语法还可以这样用: 
如果INSERT多行记录(假设 a 为主键或 a 是一个 UNIQUE索引列):

复制代码代码如下:

INSERT INTO TABLE (a,c) VALUES (1,3),(1,7) ON DUPLICATE KEY UPDATE c=c+1;


执行后, c 的值会变为 4 (第二条与第一条重复, c 在原值上+1).

复制代码代码如下:

INSERT INTO TABLE (a,c) VALUES (1,3),(1,7) ON DUPLICATE KEY UPDATE c=VALUES(c);


执行后, c 的值会变为 7 (第二条与第一条重复, c 在直接取重复的值7). 
注意:ON DUPLICATE KEY UPDATE只是MySQL的特有语法,并不是SQL标准语法! 
这个语法和适合用在需要 判断记录是否存在,不存在则插入存在则更新的场景.

INSERT INTO .. ON DUPLICATE KEY更新多行记录
如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则执行旧行UPDATE;如果不会导致唯一值列重复的问题,则插入新行。例如,如果列a被定义为UNIQUE,并且包含值1,则以下两个语句具有相同的效果:

复制代码代码如下:

INSERT INTO TABLE (a,b,c) 
VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
UPDATE TABLE SET c=c+1 WHERE a=1;


如果行作为新记录被插入,则受影响行的值为1;如果原有的记录被更新,则受影响行的值为2。
如果你想了解更多关于INSERT INTO .. ON DUPLICATE KEY的功能说明,详见MySQL参考文档:13.2.4. INSERT语法

现在问题来了,如果INSERT多行记录, ON DUPLICATE KEY UPDATE后面字段的值怎么指定?要知道一条INSERT语句中只能有一个ON DUPLICATE KEY UPDATE,到底他会更新一行记录,还是更新所有需要更新的行。这个问题困扰了我很久了,其实使用VALUES()函数一切问题都解决了。

举个例子,字段a被定义为UNIQUE,并且原数据库表table中已存在记录(2,2,9)和(3,2,1),如果插入记录的a值与原有记录重复,则更新原有记录,否则插入新行:

复制代码代码如下:

INSERT INTO TABLE (a,b,c) VALUES 
(1,2,3),
(2,5,7),
(3,3,6),
(4,8,2)
ON DUPLICATE KEY UPDATE b=VALUES(b);


以上SQL语句的执行,发现(2,5,7)中的a与原有记录(2,2,9)发生唯一值冲突,则执行ON DUPLICATE KEY UPDATE,将原有记录(2,2,9)更新成(2,5,9),将(3,2,1)更新成(3,3,1),插入新记录(1,2,3)和(4,8,2)

 

mysql DUPLICATE KEY UPDATE 死锁问题

DUPLICATE KEY UPDATE batch执行时出死锁错误

 

背景知识

一、 mysql  insert 与 duplicate key:

典型的插入语句:

多条:INSERT INTO tablename (columnA, columnB, columnC)

VALUES ('a', 1, 2), ('b', 7, 5)

单条:INSERT INTO tablename SET columnA='a', columnB=1, columnC=2

复制:INSERT [options1] [INTO] tablename [ (columnlist) ]
SELECT …

若表已设置主键如columnA,重复的插入无效

ERROR 1062 (23000): Duplicate entry 'value' for key 'PRIMARY'

如果数据库中已有某条数据,以下的两条语句可等同:

INSERT INTO tablename (id, data) VALUES (1, 10)
ON DUPLICATE KEY UPDATE data=data+10;
UPDATE tablename SET data=data+10 WHERE id=1;

duplicate key语句一般应用在 格式化多条更新语句:

INSERT INTO tablename (id, data) VALUES (1, 10), (2, 15)
ON DUPLICATE KEY UPDATE data=data+VALUE(data)

 

二、innodb表提高插入效率

查询表使用的引擎:  show create table tablename;

innodb 的存储引擎提供行级锁,支持共享锁和排他锁两种锁定模式,以及四种不同的隔离级别。

对于Innodb 类型的表,我们有以下几种方式可以提高导入的效率:
a. 因为Innodb 类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺
序排列,可以有效的提高导入数据的效率。如果Innodb 表没有主键,那么系统会默认
创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这个优势提高
导入数据的效率。
b. 在导入数据前执行SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET
UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
c. 如果应用使用自动提交的方式,建议在导入前执行SET AUTOCOMMIT=0,关闭自动
提交,导入结束后再执行SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率。

如果如果你同时从同一客户插入很多行,使用多个值表的INSERT 语句。这比使用分开INSERT 语句快(在一些情况中几倍)。

你从不同客户插入很多行,能通过使用INSERT DELAYED 语句得到更高的速度。Delayed 的含义是让insert 语句马上执行,其实数据都被放在内存的队列中,并没有真正写入磁盘;这比每条语句分别插入要快的多;LOW_PRIORITY 刚好相反,在所有其他用户对表的读写完后才进行插入;

 

在项目中遇到的问题时,使用了这种insert处理,但是分库分表,数据表类型为innodb,  tablename各不相同,duplicate key只是用于合并update和insert语句。

 "java.sql.BatchUpdateException: Deadlock found when trying to get lock; try restarting transaction" 错误状况为 第一个插入即出错,或一个batch中重复一个key,插入多个值。 貌似mysql有这个bug(http://bugs.mysql.com/bug.php?id=52020

使用threadlocal去获取操作数据库的对象,static对象,获取pool的连接并执行批处理方法

 

mysql DUPLICATE KEY UPDATE 性能问题

 

1   编写目的

1.  测试 replace into 引发死锁

2.  测试 replace 和INSET INTO  ***  ON DUPLICATE KEY UPDATE *** 性能差

2   数据库环境说明

1、 数据库系统:

名称:Mysql 5.5.31

引擎:innodb

       字符集:UTF8

       安装方式:源码编译安装   

2、 数据库部署环境:

软硬件环境:Linux(CentOS-6.2-x86_64)

 

 

3   测试工具

Mysql 自带  Mysqlslap

4   测试过程

所有操作前重启mysql,避免缓存。

 

 

测试表:

CREATE TABLE`test_replace_into` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `wechat_init_code` int(11) NOT NULL,

  `used` varchar(50) DEFAULT '0',

  `expire` int(11) NOT NULL DEFAULT '0',

  PRIMARY KEY (`id`),

  UNIQUE KEY `ii` (`wechat_init_code`)

) ENGINE=InnoDBDEFAULT CHARSET=utf8;

insert_on_duplicate.sql

SET@mm=ROUND(RAND()*100000);

SET@nn=ROUND(RAND()*100000);

INSERT INTOtest.`test_replace_into`(wechat_init_code,used,expire) VALUES (@mm,@nn,@nn) ONDUPLICATE KEY UPDATE used =@nn,expire=@nn ;

replace_into.sql:

SET@mm=ROUND(RAND()*100000);

SET @nn=ROUND(RAND()*100000);

REPLACE INTOtest.`test_replace_into` (`wechat_init_code`,`used`,`expire`) VALUES(@mm,@nn,@nn);

insert_on_duplicate_with_select.sql:

SET@mm=ROUND(RAND()*100000);

SET@nn=ROUND(RAND()*100000);

INSERT INTOtest.`test_replace_into`(wechat_init_code,used,expire) VALUES (@mm,@nn,@nn) ONDUPLICATE KEY UPDATE used =@nn,expire=@nn ;

CALLtest.`proc_test_replace_int`();

replace_into_with_select.sql:

SET@mm=ROUND(RAND()*100000);

SET@nn=ROUND(RAND()*100000);

REPLACE INTOtest.`test_replace_into` (`wechat_init_code`,`used`,`expire`) VALUES(@mm,@nn,@nn);

CALLtest.`proc_test_replace_int`();

test.`proc_test_replace_int`()

DELIMITER $$

USE `test`$$

DROP PROCEDURE IFEXISTS `proc_test_replace_int`$$

CREATEDEFINER=`root`@`%` PROCEDURE `proc_test_replace_int`()

BEGIN  

    SET @mm=ROUND(RAND()*100000);

    PREPARE sql2 FROM 'SELECT * FROMtest.`test_replace_into`  LIMIT ?,10 ;';

    EXECUTE sql2 USING @mm;

    END$$

DELIMITER ;

 

 

4.1 全更新操作,含自增ID主键,唯一索引

前置操作A:建表:

前置操作B:使用文件(2.test_data.sql)填充数据。

 

测试语句:

servicemysql restart

mysqlslap  -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="insert_on_duplicate.sql"

结果:

 

 

servicemysql restart

mysqlslap  -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="replace_into.sql"

结果:

 

4.1.1    结论:在这个情况下, replace into 的死锁概率高, 效率略高

4.2 全更新操作,不含ID,唯一索引为主键

前置操作A:删除表中的自增ID,进行测试

 

测试语句:

 

servicemysql restart

mysqlslap  -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="insert_on_duplicate.sql"

 

 

 

servicemysql restart

mysqlslap  -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="replace_into.sql"


 

4.2.1    结论:这个情况性能接近,数据增加到100W是出现少量慢日志

4.3 初始空数据,增加修改,含自增ID主键,唯一索引

mysql-uroot -proot -e 'TRUNCATE TABLE test.`test_replace_into`;'

mysqlslap  -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="replace_into.sql"

 

 

 

mysql -uroot-proot -e 'TRUNCATE TABLE test.`test_replace_into`;'

mysqlslap -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="insert_on_duplicate.sql"

 

 

结论: replace into容易死锁

4.4 初始空数据,增加修改,不含ID,唯一索引为主键

mysql-uroot -proot -e 'TRUNCATE TABLE test.`test_replace_into`;'

mysqlslap  -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="replace_into.sql"

 

 

mysql-uroot -proot -e 'TRUNCATE TABLE test.`test_replace_into`;'

mysqlslap -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=10--query="insert_on_duplicate.sql"

 

 

结论: 接近

4.5 全更新操作,不含ID,唯一索引为主键,增加查询

前置操作: 数据扩充100W

service mysql restart

mysqlslap -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=5--query="replace_into_with_select.sql"

 

service mysql restart

mysqlslap -uroot -proot --delimiter=";" --concurrency=1000  --number-of-queries=10000 --iterations=5--query="insert_on_duplicate_with_select.sql"

 

4.5.1   结论:接近,在数据库数据量达到100W时,慢日志明显暴增.  15000的1秒慢日志,两个语句慢日志数量接近

5   结论

带自增ID,使用replace 容易死锁,不要使用replace into,效率接近。

当数据量达到100W基本是,单纯修改,少量慢日志,同时的改查,慢日志明显。两者性能接近。

慢日志频繁时应该考虑降低写入并发。

 

+

+

+

-

-

-

 

分享到:
评论

相关推荐

    mysql数据库Insert语句后面加ON DUPLICATE KEY UPDATE,保证唯一性1

    `getInsertSqlStr()`方法使用`StringBuffer`构建`INSERT`语句的列名、列值和`ON DUPLICATE KEY UPDATE`部分。它遍历`fieldMap`,为每个键生成对应的`UPDATE`语句。注意到,`duplicateSb`中的每个键都跟随`= values(`...

    MySQL的Replace into 与Insert into on duplicate key update真正的不同之处

    MySQL中的`REPLACE INTO`和`INSERT INTO ... ON DUPLICATE KEY UPDATE`是两种处理数据冲突的方法,它们在处理已有键值冲突时的行为有所不同。这两种语句都是在插入新记录时,如果发现存在相同的唯一键值,则采取不同...

    mysql 中 replace into 与 insert into on duplicate key update 的用法和不同点实例分析

    在MySQL中,`REPLACE INTO` 和 `INSERT INTO ON DUPLICATE KEY UPDATE` 是两种处理数据插入时冲突的方法,主要用于处理当试图插入一条记录,而该记录的唯一键或主键已经在表中存在的情况。这两种方法都可以实现如果...

    [mysql]mysql通过on duplicate key update实现批量插入或更新(csdn)————程.pdf

    在MySQL数据库中,`ON DUPLICATE KEY UPDATE` 是一个非常实用的特性,它允许你在执行INSERT语句时,如果插入的数据违反了唯一性约束(即存在相同的唯一索引),则自动执行UPDATE操作来更新已有记录。这个功能在处理...

    Mysql中Insert into xxx on duplicate key update问题

    INSERT INTO table(a, b, c) VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = c + 1; UPDATE table SET c = c + 1 WHERE a = 1; ``` 当尝试插入的记录 `(1, 2, 3)` 中的 `a` 值已存在于表中时,`ON DUPLICATE KEY ...

    mysql如何实现 如果存在就update更新,不存在再insert插入.zip

    在MySQL数据库中,如果你需要执行一个操作,即当数据存在时进行更新,如果不存在则进行插入,你可以使用`INSERT INTO...ON DUPLICATE KEY UPDATE`语句。这个功能强大的语句结合了`INSERT`和`UPDATE`操作,允许你在...

    mysql ON DUPLICATE KEY UPDATE语句示例

    在MySQL数据库中,`ON DUPLICATE KEY UPDATE` 是一个非常实用的特性,它允许你在插入新数据时,如果遇到重复的唯一键值,自动执行更新操作,而不是抛出错误。这个功能大大简化了数据处理的流程,特别是当你需要在一...

    insert into … on duplicate key update / replace into 多行数据介绍

    ON DUPLICATE KEY UPDATE` 和 `REPLACE INTO` 是MySQL中处理批量插入并更新已有数据的两种有效策略,它们提供了在保持数据完整性和性能之间平衡的解决方案。根据具体业务需求和数据约束,选择合适的方法来优化数据...

    深入mysql ON DUPLICATE KEY UPDATE 语法的分析

    mysql “ON DUPLICATE KEY UPDATE” 语法如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则在出现重复值的行执行UPDATE;如果不会导致唯一值列...

    INSERT INTO .. ON DUPLICATE KEY更新多行记录

    ON DUPLICATE KEY UPDATE` 是 MySQL 数据库中的一种高效操作,它结合了插入新记录和更新已有记录的功能。这个语句主要用于处理唯一性约束冲突,如 PRIMARY KEY 或 UNIQUE 索引的情况。当试图插入的记录与现有记录在...

    MySQL中如何处理重复数据(Duplicate)?

    ON DUPLICATE KEY UPDATE 语句是在 MySQL 中处理重复数据的常用方法。该语句在插入数据时,如果遇到唯一键冲突(即主键或有唯一索引的字段),则会执行更新操作。示例: INSERT INTO table_name (col1, col2, col3...

    MYSQL的REPLACE和ON DUPLICATE KEY UPDATE语句介绍解决问题实例

    ON DUPLICATE KEY UPDATE`都是MySQL提供的强大工具,它们可以帮助我们更高效、更精确地管理数据库中的数据,特别是处理需要确保数据唯一性和排序顺序的情况下。通过合理利用这些语句,我们可以减少数据库操作的复杂...

    mysql 批量更新及效率对比

    MySQL 批量更新的高效方法 MySQL 批量更新是指在 MySQL 数据库中批量更新多... On Duplicate Key Update 语句可以大大提高更新效率,而使用临时表的方法也可以提高效率,但是需要用户有 temporary 表的 create 权限。

    深入mysql "ON DUPLICATE KEY UPDATE" 语法的分析

    MySQL的`ON DUPLICATE KEY UPDATE`语法是一种特殊的数据插入机制,它允许你在尝试插入新记录时,如果遇到唯一约束冲突(比如主键或唯一索引的值已经存在),则自动更新已有记录。这个特性在处理数据导入、同步或批量...

    mysql 批量更新及效率对比.docx

    Replace Into 和 Insert Into On Duplicate Key Update 两种方法都可以实现批量更新,但它们之间有着很大的区别。 Replace Into 操作本质是对重复的记录先 delete 后 insert,如果更新的字段不全会将缺失的字段置为...

Global site tag (gtag.js) - Google Analytics