面對 320 萬條數據的更新任務,初期腳本每秒僅處理 3~5 行,預計耗時 24 小時。通過定位索引失效、優化 WHERE 條件、引入主鍵範圍分批提交,最終將速度提升至 30 行/秒,總耗時壓縮至 3 小時。本文復盤兩大典型優化場景。
fuckSpeed 僅有聯合索引 uin_id (uin, id)。SELECT id, url FROM fuckSpeed WHERE id BETWEEN 101 AND 200,再循環 UPDATE ... WHERE id = ?。-- 查詢計劃顯示:type=ALL,未命中索引 EXPLAIN SELECT id, url FROM fuckSpeed WHERE id >= 0 AND id <= 200; -- 結果:possible_keys=NULL, key=NULL, rows=324746, Using where
聯合索引生效要求 WHERE 條件必須包含最左列。此處查詢與更新均只用 id,導致索引失效,退化為全表掃描(0.18 秒/次)。
SELECT uin, id, url FROM fuckSpeed WHERE id BETWEEN ...(應用層需保存 uin)。UPDATE fuckSpeed SET type=?, typeid=? WHERE uin=? AND id=?。-- 驗證索引生效 EXPLAIN SELECT uin, id FROM fuckSpeed WHERE uin=10023 AND id=162; -- 結果:type=ref, key=uin_id, key_len=12, rows=4, Using index
效果:單進程速度從 3~5 行/秒 飆升至 30+ 行/秒,總耗時從 24h 降至 3h。
pid 更新 brand_id,其中 2 張表達千萬級。UPDATE table SET brand_id = ? WHERE pid = ? AND brand_id = 0。pid 無索引,每次更新觸發全表掃描(1000 萬行),且不同 pid 需重複執行,MySQL 主從同步延遲飆升至 40 分鐘。利用主鍵 id(聚簇索引,自帶有序性)將大表邏輯切片:
-- 優化後:增加主鍵範圍條件,每次只掃 1000 行 UPDATE $tableName$ SET brand_id = #newBrandId# WHERE pid = #pid# AND brand_id = 0 AND id BETWEEN #startNum# AND #endNum#;
type 非 ALL、key 非 NULL。這兩個案例揭示了 MySQL 更新性能的兩大殺手:索引設計缺陷與大事務長鎖定。針對性優化,立竿見影。