參數調優是「養護」,架構與代碼層優化是「手術」。五大手段直擊核心瓶頸。
START TRANSACTION;
INSERT INTO orders (user_id, amount) VALUES (100, 99.9);
UPDATE inventory SET stock = stock - 1 WHERE sku = 'A001' AND stock > 0;
COMMIT;
-- 任一失敗 → ROLLBACK,保證原子性
關鍵點:
READ COMMITTED (RC) + binlog_format=ROW 兼顧性能與一致性 (5.7+ 默認)。Deadlock found 重試 (指數退避),InnoDB 自動回滾受害者。
-- 表鎖 (MyISAM/InnoDB 皆支援,但 InnoDB 推薦行鎖)
LOCK TABLES inventory WRITE, orders WRITE;
SELECT stock FROM inventory WHERE sku='A001';
UPDATE inventory SET stock=stock-1 WHERE sku='A001';
UNLOCK TABLES;
適用場景:
CREATE TABLE customers (
id INT PRIMARY KEY
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id)
ON DELETE CASCADE
ON UPDATE RESTRICT
) ENGINE=InnoDB;
收益:
ON DELETE CASCADE 級聯刪除,應用層無需手動清理。代價:
| 索引策略 | 口訣 | 實例 |
|---|---|---|
| 最左前綴 | 聯合索引 (a,b,c) → WHERE a=1 / a=1 AND b=2 / a=1 AND b=2 AND c=3 生效 | INDEX idx_abc (a,b,c) |
| 覆蓋索引 | SELECT 欄位全在索引中 → Using index,避免回表 | INDEX idx_uid_status (user_id, status) INCLUDE (amount) (8.0) |
| 區分度優先 | 高區分度列放前 (性別/狀態低區分度勿作首列) | INDEX idx_status_uid (status, user_id) ❌ → INDEX idx_uid_status (user_id, status) ✅ |
| 避免函數殺索引 | WHERE YEAR(dt)='2024' ❌ → WHERE dt >= '2024-01-01' AND dt < '2025-01-01' ✅ | 範圍查詢走索引 |
| LIKE 後綴匹配 | name LIKE '%abc' ❌ (全掃) → 反轉存儲/全文索引/Trigram | 全文索引 FULLTEXT |
-- 1. OR 改 UNION (索引合併)
SELECT * FROM t WHERE a=1 OR b=2;
→ SELECT * FROM t WHERE a=1 UNION SELECT * FROM t WHERE b=2;
-- 2. IN 子查詢改 JOIN (5.6+ 半連接優化但不穩)
SELECT * FROM t1 WHERE id IN (SELECT t1_id FROM t2 WHERE status=1);
→ SELECT t1.* FROM t1 JOIN t2 ON t1.id=t2.t1_id WHERE t2.status=1;
-- 3. 分頁優化 (游標法)
SELECT * FROM orders WHERE user_id=100 ORDER BY id LIMIT 100000, 20;
→ SELECT * FROM orders WHERE user_id=100 AND id > 999999 ORDER BY id LIMIT 20;
-- 4. 聚合下推
SELECT COUNT(*) FROM orders WHERE user_id=100;
-- 覆蓋索引 (user_id) 直接掃描索引葉子節點,極快
pt-query-digest 定期分析 Top 20。EXPLAIN 每條核心 SQL,消除 ALL/filesort/temporary。pt-index-usage / pt-duplicate-key-checker 找廢棄/重複索引。