解决问题: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,唯一索引为主键,增加查询
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基本是,单纯修改,少量慢日志,同时的改查,慢日志明显。两者性能接近。
慢日志频繁时应该考虑降低写入并发。
+
+
+
-
-
-
相关推荐
`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数据库中,`ON DUPLICATE KEY UPDATE` 是一个非常实用的特性,它允许你在执行INSERT语句时,如果插入的数据违反了唯一性约束(即存在相同的唯一索引),则自动执行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数据库中,如果你需要执行一个操作,即当数据存在时进行更新,如果不存在则进行插入,你可以使用`INSERT INTO...ON DUPLICATE KEY UPDATE`语句。这个功能强大的语句结合了`INSERT`和`UPDATE`操作,允许你在...
在MySQL数据库中,`ON DUPLICATE KEY UPDATE` 是一个非常实用的特性,它允许你在插入新数据时,如果遇到重复的唯一键值,自动执行更新操作,而不是抛出错误。这个功能大大简化了数据处理的流程,特别是当你需要在一...
ON DUPLICATE KEY UPDATE` 和 `REPLACE INTO` 是MySQL中处理批量插入并更新已有数据的两种有效策略,它们提供了在保持数据完整性和性能之间平衡的解决方案。根据具体业务需求和数据约束,选择合适的方法来优化数据...
mysql “ON DUPLICATE KEY UPDATE” 语法如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则在出现重复值的行执行UPDATE;如果不会导致唯一值列...
ON DUPLICATE KEY UPDATE` 是 MySQL 数据库中的一种高效操作,它结合了插入新记录和更新已有记录的功能。这个语句主要用于处理唯一性约束冲突,如 PRIMARY KEY 或 UNIQUE 索引的情况。当试图插入的记录与现有记录在...
ON DUPLICATE KEY UPDATE 语句是在 MySQL 中处理重复数据的常用方法。该语句在插入数据时,如果遇到唯一键冲突(即主键或有唯一索引的字段),则会执行更新操作。示例: INSERT INTO table_name (col1, col2, col3...
ON DUPLICATE KEY UPDATE`都是MySQL提供的强大工具,它们可以帮助我们更高效、更精确地管理数据库中的数据,特别是处理需要确保数据唯一性和排序顺序的情况下。通过合理利用这些语句,我们可以减少数据库操作的复杂...
MySQL 批量更新的高效方法 MySQL 批量更新是指在 MySQL 数据库中批量更新多... On Duplicate Key Update 语句可以大大提高更新效率,而使用临时表的方法也可以提高效率,但是需要用户有 temporary 表的 create 权限。
MySQL的`ON DUPLICATE KEY UPDATE`语法是一种特殊的数据插入机制,它允许你在尝试插入新记录时,如果遇到唯一约束冲突(比如主键或唯一索引的值已经存在),则自动更新已有记录。这个特性在处理数据导入、同步或批量...
Replace Into 和 Insert Into On Duplicate Key Update 两种方法都可以实现批量更新,但它们之间有着很大的区别。 Replace Into 操作本质是对重复的记录先 delete 后 insert,如果更新的字段不全会将缺失的字段置为...