1. 程式人生 > 資料庫 >mysql批量更新及拆分

mysql批量更新及拆分

        前陣子有個指令碼執行特別慢,根據一張表中查詢的資料來更新另一張表資料。每晚18:00開始執行,之前一般大概執行到21、22點左右,最近有幾次竟然直到凌晨才跑完,這就有點接受不了了。捋了一下指令碼,是每查出一條就去更新一條,每次更新時都得連庫、操作、然後關閉。就想著能不能一次更新多條呢,也就是寫個批量更新語句。
        假設表結構如下:

CREATE TABLE `test_book` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `book_name` varchar(32) NOT NULL default '' COMMENT '書名',
  `uid` int unsigned NOT NULL DEFAULT 0 COMMENT '作者id',
  `u_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  `c_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8

        如果想根據id批量更新book_name欄位,可以如下書寫:

UPDATE test_book SET
    book_name = CASE id
        WHEN 1 THEN '三國演義'
        WHEN 2 THEN '紅樓夢'
        WHEN 3 THEN '水滸傳'
    END
WHERE id IN (1,2,3)

        這樣一條語句即可更新三條記錄,對id=1的書名更新為三國演義,id=2的書名更新為紅樓夢,以此類推。如果是同時更新多個欄位,譬如書名和作者id:

UPDATE test_book SET
    book_name = CASE id
        WHEN 1 THEN '三國演義'
        WHEN 2 THEN '紅樓夢'
        WHEN 3 THEN '水滸傳'
    END,
    uid = CASE id
        WHEN 1 THEN 4
        WHEN 2 THEN 5
        WHEN 3 THEN 6
    END
WHERE id IN (1,2,3)

指令碼改成批量更新後,執行時間瞬間成為原來的10%,十幾分鐘頂多半小時就執行完了。

然而隨著批量更新的資料量越來越大,又報了另一個問題導致指令碼中斷了。

Communication link failure: 1153 Got a packet bigger than 'max_allowed_packet' bytes

檢視mysql該引數配置:

mysql> select @@max_allowed_packet;
+----------------------+
| @@max_allowed_packet |
+----------------------+
|             16777216 |
+----------------------+
1 row in set (0.01 sec)

也就是16M。解決方法有兩種,要麼聯絡dba擴大該引數值;要麼拆分資料。我這裡是兩種方法都採用了,一方面聯絡dba將該引數值調整為32M,一方面在程式碼層面做了修改,一次只更新20000條。

$total = count($res);
echo '共'. $total. "條資料\n";
$k = 0;
while ($k < $total) {
     $temp = array_slice($res, $k, 20000);
     $success = $order->batchUpdateOrderPayStatus($temp);
     echo '成功修改'. $success. "\n";
     $k += 20000;
}

至此,批量更新徹底解決。