mysql 批量更新共有以下四种办法
1、 replace into 批量更新
replace into 表名l (id,字段1) values (1,'2'),(2,'3'),...(x,'y');
2、insert into ...on duplicate key update批量更新
insert into 表名l (id,字段1) values (1,'2'),(2,'3'),...(x,'y') on duplicate key update 字段1=values(字段1);
3.创建临时表,先更新临时表,然后从临时表中update
1create temporary table tmp(id int(4) primary key,dr varchar(50)); 2insert into tmp values (0,'gone'), (1,'xx'),...(m,'yy'); 3update test_tbl, tmp set test_tbl.dr=tmp.dr where test_tbl.id=tmp.id;
注意:这种方法需要用户有temporary 表的create 权限。
4、使用mysql 自带的语句构建批量更新
mysql 实现批量 可以用点小技巧来实现:

1UPDATE yoiurtable 2 SET dingdan = CASE id 3 WHEN 1 THEN 3 4 WHEN 2 THEN 4 5 WHEN 3 THEN 5 6 END 7WHERE id IN (1,2,3)

这句sql 的意思是,更新dingdan 字段,如果id=1 则dingdan 的值为3,如果id=2 则dingdan 的值为4……
where部分不影响代码的执行,但是会提高sql执行的效率。确保sql语句仅执行需要修改的行数,这里只有3条数据进行更新,而where子句确保只有3行数据执行。
例子:
1UPDATE book 2 SET Author = CASE id 3 WHEN 1 THEN '黄飞鸿' 4 WHEN 2 THEN '方世玉' 5 WHEN 3 THEN '洪熙官' 6 END 7 WHERE id IN (1,2,3)
如果更新多个值的话,只需要稍加修改:
1UPDATE categories 2 SET dingdan = CASE id 3 WHEN 1 THEN 3 4 WHEN 2 THEN 4 5 WHEN 3 THEN 5 6 END, 7 title = CASE id 8 WHEN 1 THEN 'New Title 1' 9 WHEN 2 THEN 'New Title 2' 10 WHEN 3 THEN 'New Title 3' 11 END 12WHERE id IN (1,2,3)
到这里,已经完成一条mysql语句更新多条记录了。
php中用数组形式赋值批量更新的代码:
1$display_order = array( 2 1 => 4, 3 2 => 1, 4 3 => 2, 5 4 => 3, 6 5 => 9, 7 6 => 5, 8 7 => 8, 9 8 => 9 10); 11$ids = implode(',', array_keys($display_order)); 12$sql = "UPDATE categories SET display_order = CASE id "; 13foreach ($display_order as $id => $ordinal) { 14 $sql .= sprintf("WHEN %d THEN %d ", $id, $ordinal); 15} 16$sql .= "END WHERE id IN ($ids)"; 17echo $sql;
这个例子,有8条记录进行更新。代码也很容易理解,你学会了吗
更新 100000条数据的性能就测试结果来看,测试当时使用replace into性能较好。
replace into 和 insert into on duplicate key update的不同在于:
- replace into 操作本质是对重复的记录先delete 后insert,如果更新的字段不全会将缺失的字段置为缺省值,用这个要悠着点!否则不小心清空大量数据可不是闹着玩的!!!
- insert into 则是只update重复记录,不会改变其它字段。
相同点:
(1)没有key的时候,replace与insert .. on deplicate udpate相同。
(2)有key的时候,都保留主键值,并且auto_increment自动+1。
不同点
有key的时候,replace是delete老记录,而录入新的记录,所以原有的所有记录会被清除,这个时候,如果replace语句的字段不全的话,有些原有的比如例子中c字段的值会被自动填充为默认值。
而insert .. deplicate update则只执行update标记之后的sql,从表象上来看相当于一个简单的update语句。
但是实际上,根据我推测,如果是简单的update语句,auto_increment不会+1,应该也是先delete,再insert的操作,只是在insert的过程中保留除update后面字段以外的所有字段的值。
所以两者的区别只有一个,insert .. on deplicate udpate保留了所有字段的旧值,再覆盖然后一起insert进去,而replace没有保留旧值,直接删除再insert新值。
从底层执行效率上来讲,replace要比insert .. on deplicate update效率要高,但是在写replace的时候,字段要写全,防止老的字段数据被删除。
以下代码作为简单测试
1<?php 2/** 3 * CREATE TABLE `demo` ( 4 * `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 5 * `data` varchar(255) NOT NULL, 6 * PRIMARY KEY (`id`) 7 * ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 */ 9 10/* 11 * 连接数据库 12 */ 13$dsn = 'mysql:host=127.0.0.1;dbname=testdb;'; 14$user = 'root'; 15$password = '123456'; 16try { 17 $dbh = new PDO( $dsn , $user , $password ); 18} catch ( \Exception $e ) { 19 throw new \Exception( $e->getMessage () ); 20} 21 22/* 23 * 调整 Mysql Server接受的数据包 24 */ 25$dbh->exec ( "set global max_allowed_packet = 2*1024*1024*1024" ); 26 27/* 28 * 测试记录总数 29 */ 30$rowsCount = 10000; 31 32/* 33 * 1 普通方式,逐行写入测试数据 34 */ 35$time_start = microtime ( true ); 36try { 37 for ( $i = 1 ; $i <= $rowsCount ; $i ++ ) { 38 $sql = "insert into demo( data ) value ('" . mt_rand ( 10000000 , 99999999 ) . "')"; 39 $dbh->exec ( $sql ); 40 } 41} catch ( \Exception $e ) { 42 throw new \Exception( $e->getMessage () ); 43} 44$time_end = microtime ( true ); 45$time = $time_end - $time_start; 46echo "1 Execution time: {$time} s" . PHP_EOL; 47 48/* 49 * 2 事务 50 */ 51$time_start = microtime ( true ); 52$dbh->beginTransaction (); 53try { 54 for ( $i = 1 ; $i <= $rowsCount ; $i ++ ) { 55 $sql = "insert into demo(data) value ('" . mt_rand ( 10000000 , 99999999 ) . "')"; 56 $dbh->exec ( $sql ); 57 } 58 $dbh->commit (); 59} catch ( \Exception $e ) { 60 $dbh->rollBack (); 61 throw new \Exception( $e->getMessage () ); 62} 63 64$time_end = microtime ( true ); 65$time = $time_end - $time_start; 66echo "2 Execution time: {$time} s" . PHP_EOL; 67 68/* 69 * 3 值合并方式,values (...),(...) 70 */ 71$time_start = microtime ( true ); 72try { 73 $sql = "insert into demo( data ) values "; 74 for ( $i = 1 ; $i <= $rowsCount ; $i ++ ) { 75 $sql .= "('" . mt_rand ( 10000000 , 99999999 ) . "'),"; 76 } 77 $dbh->exec ( rtrim ( $sql , ',' ) ); 78} catch ( \Exception $e ) { 79 throw new \Exception( $e->getMessage () ); 80} 81$time_end = microtime ( true ); 82$time = $time_end - $time_start; 83echo "3 Execution time: {$time} s " . PHP_EOL; 84 85/* 86 * 4 合并加事务 87 */ 88$time_start = microtime ( true ); 89$dbh->beginTransaction (); 90try { 91 $sql = "insert into demo( data ) values "; 92 for ( $i = 1 ; $i <= $rowsCount ; $i ++ ) { 93 $sql .= "('" . mt_rand ( 10000000 , 99999999 ) . "'),"; 94 } 95 $dbh->exec ( rtrim ( $sql , ',' ) ); 96 $dbh->commit (); 97} catch ( \Exception $e ) { 98 $dbh->rollBack (); 99 throw new \Exception( $e->getMessage () ); 100} 101$time_end = microtime ( true ); 102$time = $time_end - $time_start; 103echo "4 Execution time : {$time} s " . PHP_EOL; 104 105输出结果: 106 10710w数据: 108 1091 Execution time: 269.58895611763 s 1102 Execution time: 25.353534936905 s 1113 Execution time: 1.2171220779419 s 1124 Execution time : 1.1611158847809 s 113 114 11550w数据: 116 1171 Execution time: 1358.3988881111 s 1182 Execution time: 119.97599983215 s 1193 Execution time: 6.7320001125336 s 1204 Execution time : 6.4200000762939 s
总结:
在数据量大的时候,进行数据合并形式"values(...),(...),...",如果有数据完整性的需求,采用事务,相对来说能好些.