fuckSpeed,32 萬筆資料,唯一聯合索引 uin_id (uin, id)url 欄位匹配規則,更新新增欄位 type、typeidSELECT ... WHERE id BETWEEN ... → 處理 → UPDATE ... WHERE id = ?-- 初始查詢 SELECT id, url FROM fuckSpeed WHERE id >= 101 AND id <= 200; EXPLAIN 顯示:type=ALL, key=NULL, rows=324746 -- 全表掃描!
原因: 聯合索引 (uin, id) 僅在 WHERE 條件包含 uin(最左列)或 uin + id 時生效。單獨查 id 導致索引失效,退化為全表掃描。
-- 加上 uin 後 SELECT uin, id, url FROM fuckSpeed WHERE uin = 10023 AND id = 162; EXPLAIN 顯示:type=ref, key=uin_id, rows=4, Extra=Using index -- 秒級!
SELECT 時一併撈取 uin:SELECT uin, id, url ...UPDATE 時帶上 uin:UPDATE ... SET type=?, typeid=? WHERE uin=? AND id=?優化後效能: 30+ rows/sec,總耗時從 24h 降至 3 小時內。
| # | 原則 | 說明 |
|---|---|---|
| 1 | 統計行數用獨立統計表 | InnoDB COUNT(*) 全表掃描,改用 MyISAM 統計表定期同步 |
| 2 | 業務邏輯勿在 DB 做運算 | 應用層計算完成再寫入,減少 CPU 壓力 |
| 3 | 避免負向查詢與前導模糊 | NOT IN、!=、%keyword% 皆導致索引失效 |
| 4 | 索引列上禁用函數/運算 | WHERE YEAR(dt) = 2023 → WHERE dt >= '2023-01-01' AND dt < '2024-01-01' |
| 5 | 禁用 SELECT * | 只取需要欄位,利於覆蓋索引 |
| 6 | 善用 LIMIT 限制回傳行數 | 減少網路傳輸與記憶體 |
| 7 | WHERE 列勿用函數 | 同第 4 點,函數導致索引失效 |
| 8 | 避免隱式類型轉換 | 字串加引號、數字不加,否則索引失效 |
| 9 | SQL 關鍵字大寫 | 減少解析快取分裂(大小寫不同視為不同 SQL) |
| 10 | 小結果集驅動大結果集 | JOIN 時小表在前,或用子查詢先縮小駕駛表 |
| 11 | 開啟慢查詢日誌定期 EXPLAIN | 建立持續優化閉環 |
id 非唯一且選擇度低,單列索引效果有限uin + id,聯合索引已覆蓋,額外單列索引增加寫入開銷id 的高頻場景,可評估新增 idx_id (id),但必須經負載測試驗證核心教訓: 索引設計必須對齊查詢模式。
EXPLAIN是驗證索引生效的唯一標準——沒有 EXPLAIN 的優化都是耍流氓。大批量 DML 前,務必先跑樣本驗證執行計畫,避免上線後發現「全表掃描」的災難。