原生mysql的批量更新及性能测试

一、前言

      我们在做批量更新的时候,经常会使用到框架的批量更新API,那么原生的mysql要怎么做批量更新呢,下面我们来研究下原生的批量更新以及性能测试。(如果有框架,谁又愿意用原生的呢!!!

mysql环境:

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.53    |
+-----------+
1 row in set (0.00 sec)

二、原生的写法

1、用到的函数是case …when …then

手册手册

拼接出来的sql形如:

"update student set  click_time = 
case test_id 
WHEN 70300 THEN 1578832683 
WHEN 70301 THEN 1578832683 
END,  
installed_at = case test_id 
WHEN 70300 THEN 1578832684 
WHEN 70301 THEN 1578832684  
END WHERE test_id IN (70301,70300)

语意: 类似于编程语言中的流程控制语句,当test_id=xxx的时候,就设置click_time=xxx,否则就设置click_time= ooo。多个字段设置的话参考博主这里的写法,直接设置即可,最后面跟的in条件是限制test_id的范围。

2、php拼接sql

 $sql_pre = "update student set ";
  $sql_click_pre  = " click_time = case test_id ";
  $sql_install_pre = " installed_at = case test_id ";
  $sql_click_end = "";
  $sql_install_end = "";
  foreach($arr as $v){
    $sql_click_end .= sprintf("WHEN %d THEN %d ", $v[0], $v[1]);
    $sql_install_end .= sprintf("WHEN %d THEN %d ", $v[0], $v[2]);
  }
  // 这里拼接sql,拼接出来就是如上所示的例子
  $sql = $sql_pre.$sql_click_pre.$sql_click_end.'END, ' .$sql_install_pre.$sql_install_end. " END WHERE test_id IN ($sqls)" ;
  var_dump($sql);
  $rs = mysqli_query($link, $sql);
  if (!$rs) {
    die('更改失败: ' . mysqli_error($link));
  }
  

拼接的操作简单,就是循环数组,拼接sql即可。

3、是否能用到索引

			mysql> explain update xxxx set  click_time = case user_id WHEN 1070768 THEN 1577624803 WHEN 1025435 THEN 1577625891 END,  installed_at = case user_id WHEN 1070768 THEN 1577624904 WHEN 1025435 THEN 1577625964  END WHERE user_id IN (1070768,1025435);
+------+-------------+--------------+-------+----------------------+----------------------+---------+------+------+-------------+
| id   | select_type | table        | type  | possible_keys        | key                  | key_len | ref  | rows | Extra       |
+------+-------------+--------------+-------+----------------------+----------------------+---------+------+------+-------------+
|    1 | SIMPLE      | user_tracker | range | uniq_user_id_tracker | uniq_user_id_tracker | 8       | NULL |    2 | Using where |
+------+-------------+--------------+-------+----------------------+----------------------+---------+------+------+-------------+

      根据执行计划,显然是用到了索引的,最起码代表性能不至于太差。

三、批量更新的性能测试(50W数据)

1、首先是更新不同数量的性能展示

每次更新100:耗时:88ms	
每次更新300:耗时:105ms	
每次更新500:耗时:144ms	
每次更新1000:耗时:202ms	
每次更新1500:耗时:242ms	
每次更新2000:耗时:422ms

      这几个值都是博主这边实验10次,计算出来的平均值。从时间上来看,大于1500条之后,性能出现了急剧缩减,小于1500条数据的时候表现还不错。不过我们一般也不会一次更新这么多条数据,大部分都会分批量进行(一次循环500个之类的)

2、关于sql长度

手册手册

      sql长度的话,一般是默认16M,我们普通的sql是完全不会超过的,这里有兴趣的话,可以去参考我的另一篇博客:mysql批量插入数据,一次插入多少行数据效率最高?

3、关于in查询

      我们的sql里面是带有in查询的,不过经过博主上次的测试,in查询的性能整体表现比较平滑,没有出现性能急剧的变化,所以一般情况下正常使用即可,不用特别担心。

参考我的另一篇:mysql的in查询参数限制,多少数据量会造成性能下降?什么时候创建临时表合适?

4、关于case…when和if等的性能比较

      这两个函数性能差距不大,比对次数尽量少一些就行,很多函数的内部就是case whenifcase then等语句,最后会被转化为机器指令,速度极快(cpu处理)

参考:https://bbs.csdn.net/topics/392056484

5、为什么我的case…when用不到索引?

      博主在查资料的时候,发现有些文章里面的case..when因为没有用到索引,所以效率十分低下。最明显的两个错误,一个是在sql里面对字段进行函数计算,另一个就是类型对不上,你弄个int类型非得和string类型比较,能用到索引才怪。

case..when的索引部分就和其他字段的索引一样,按照规范去使用即可。

6、其他

参考链接:

https://www.jianshu.com/p/c19c99a60bb7 : case when的例子比较
https://www.dazhuanlan.com/2019/09/13/0a2a08989237/ : case when用不到索引的情况,因为函数影响
http://www.gaodevops.com/articles/219/mysql-you-hua-an-li-case-when-jin-xing-sql-gai-xie-you-hua?order_by=vote_count&  :case when 优化
https://juejin.im/post/5a30cb8e6fb9a0451f30edd9	:很清晰的用法
https://blog.csdn.net/qq_30038111/article/details/79611167  :case when的用法,包括简单函数和搜索函数

      最近流感猖獗,博主不幸中标,实在苦不堪言。希望各位在临近年关之际,注意身体,注意保暖,过个好年哈哈

end

发布了359 篇原创文章 · 获赞 1350 · 访问量 130万+

猜你喜欢

转载自blog.csdn.net/LJFPHP/article/details/103964927