原生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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章