當單表突破千萬、QPS 萬級、響應時間毫秒級要求並存,單點優化已無法支撐。本文從數據架構設計、SQL 改寫、索引策略、算法重構四個維度,結合實戰案例,構建系統化優化知識體系。
| 場景 | 策略 | 代價 |
|---|---|---|
| 高頻 JOIN 大表 | 冗余關聯鍵 / 廣播表 / 應用層組裝 | 寫入放大、一致性最終一致 |
| 海量單表寫入 | 分庫分表(Hash/Range/時間) | 跨分片事務、全局唯一 ID |
| 多維度查詢 | ES / ClickHouse / Doris 異構同步 | 數據延遲、運維複雜度 |
| 熱點行更新 | 隊列串行化 / Redis 計數器回寫 | 延遲持久化風險 |
INT UNSIGNED、枚舉存 TINYINT、金額存 BIGINT(分為單位)CHAR 定長高頻短字符(MD5、狀態)、VARCHAR 變長業務字段VARCHAR(20) 優於 VARCHAR(255)(索引內存、排序緩衝)形式:列 操作符 常數 或 常數 操作符 列。列參與運算/函數/隱式轉換 → 索引失效 → 全表掃描。
| 反模式 | 優化寫法 | 原理 |
|---|---|---|
WHERE col IS NULL | 默認值 0,WHERE col=0 | NULL 不進普通索引 |
WHERE col != val | 拆分範圍或 NOT IN | 否定無法走索引範圍 |
WHERE col=1 OR col=2 | UNION ALL 兩條 SQL | OR 導致全掃,UNION 走索引合併 |
WHERE col IN (1,2,3) | 連續值用 BETWEEN | IN 列表長時優化器可能放棄索引 |
LIKE '%abc%' | LIKE 'abc%' 或全文索引 | 前導通配符不可用 B+Tree |
WHERE col/2=100 | WHERE col=200 | 列運算破壞索引有序性 |
WHERE SUBSTR(col,1,4)='5378' | WHERE col LIKE '5378%' | 函數同理 |
WHERE DATEDIFF(day, dt, NOW())>21 | WHERE dt < DATE_SUB(NOW(), INTERVAL 21 DAY) | 列無運算,常數預計算 |
SELECT * | 顯式列出需要列 | 減少網絡/IO/回表,利於覆蓋索引 |
COUNT(*) 判存在 | EXISTS (SELECT 1 ...) | EXISTS 遇一停掃,COUNT 掃全表 |
NOT IN 子查詢 | NOT EXISTS / LEFT JOIN ... IS NULL | NOT IN 含 NULL 返回空、性能差 |
SELECT * FROM t FORCE INDEX(idx_name) WHERE ...(僅作臨時干預,根治靠統計信息)SELECT * FROM (SELECT id FROM t WHERE cond LIMIT 100000,10) a JOIN t USING(id) 解決深分頁回表UNION ALL 替代 UNION(去重開銷大)DISTINCT 替代 GROUP BY(無聚合函數時)| 特徵 | 聚簇 | 二級 |
|---|---|---|
| 頻繁範圍查詢 | ✓ | ✗ |
| 極少/極多不同值 | ✗ | ✗/✓ |
| 頻繁更新 | ✗ | ✓ |
| 外鍵/主鍵 | ✓ | ✓ |
實戰結論:業務主鍵(自增 ID)做聚簇,高頻範圍查詢列(如 created_at、shop_id)建二級或聯合索引。
(a,b,c):WHERE a=1 ✓、WHERE a=1 AND b=2 ✓、WHERE b=2 ✗WHERE a=1 AND b LIKE 'xyz%' 中的 b,減少回表每個索引增加:寫入放大(插入/更新/刪除維護 B+Tree)、空間佔用、統計信息收集開銷。單表索引建議 ≤ 5 個,定期 ANALYZE TABLE 更新 Cardinality。
INSERT ... VALUES (),(),()、UPDATE ... CASE WHEN大數據高併發優化無銀彈,只有架構分層、SQL 重構、索引精準、算法集合化的組合拳。建立「慢查詢日審計 → 週度索引健康檢查 → 月度架構演進評審」機制,讓優化成為持續交付流程的一環,而非救火行動。