文章目錄
一、前言
我們在做批量更新的時候,經常會使用到框架的批量更新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 when ,if
和case 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