優化器只能優化「寫得好」的 SQL。糟糕的查詢計劃經優化器也難變高效。SQL 質量決定性能上限。
INDEX(a,b,c)ANALYZE TABLE 更新統計信息DROP + CREATE INDEX 重建,消除碎片INDEX(a,b) 滿足 ORDER BY a,bsort_buffer_size-- 惡例:三層嵌套各 1000 行 → 10 億次訪問
SELECT * FROM a JOIN b ON a.id=b.a_id JOIN c ON b.id=c.b_id;
ALTER TABLE `b` ADD INDEX `idx_a_id` (`a_id`);
ALTER TABLE `c` ADD INDEX `idx_b_id` (`b_id`);
-- 原:強制全表掃描
SELECT * FROM orders WHERE (customer=104 AND order_id>1001) OR order_id=1008;
-- 優化:拆分走索引
SELECT * FROM orders WHERE customer=104 AND order_id>1001
UNION
SELECT * FROM orders WHERE order_id=1008;
-- 慢:外層每行執行一次子查詢
SELECT * FROM outer WHERE col IN (SELECT col FROM inner WHERE inner.x = outer.x);
-- 快:JOIN 或 EXISTS
SELECT o.* FROM outer o JOIN inner i ON o.col = i.col WHERE i.x = o.x;
SELECT * FROM outer o WHERE EXISTS (SELECT 1 FROM inner i WHERE i.col = o.col AND i.x = o.x);
| 慢 | 快 | 原理 |
|---|---|---|
| LIKE '%abc%' | 全文索引 / ES | 倒排索引 |
| LIKE 'abc%' | 同左,但可走前綴索引 | B+樹最左前綴 |
| zip LIKE '98___' | zip > '98000' AND zip < '99000' | 範圍查詢走索引 |
| SUBSTR(zip,2,2) > '80' | zip > 'x8000' AND zip < 'x9000' | 避免非首字符截取 |
-- 原:多表 JOIN + 排序,重複執行
SELECT c.name, r.balance, ...
FROM cust c JOIN rcvbles r ON c.id=r.cust_id
WHERE r.balance>0 AND c.postcode>'98000'
ORDER BY c.name;
-- 優化:物化中間結果
CREATE TEMPORARY TABLE tmp_cust AS
SELECT c.name, r.balance, c.postcode
FROM cust c JOIN rcvbles r ON c.id=r.cust_id
WHERE r.balance>0
ORDER BY c.name;
-- 後續多次查詢直接用臨時表
SELECT * FROM tmp_cust WHERE postcode>'98000';
⚠️ 臨時表不感知主表變更,高頻寫入場景慎用。
-- 按日期範圍分區(最常用)
CREATE TABLE `logs` (
`id` BIGINT UNSIGNED,
`created_at` DATETIME NOT NULL,
...
PRIMARY KEY (`id`, `created_at`)
) PARTITION BY RANGE (TO_DAYS(`created_at`)) (
PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')),
PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
-- 查詢自動分區裁剪
EXPLAIN SELECT * FROM `logs` WHERE `created_at` >= '2024-01-15';
# 架構圖
[寫主庫] --binlog--> [從庫1/從庫2] --查詢--> [應用]
|
+--> [Redis 緩存熱點數據]
+--> [ProxySQL 讀寫分離/查詢緩存/熔斷]
innodb_flush_method=O_DIRECT 避免雙重緩存innodb_buffer_pool_size = 物理內存 60-70%vm.swappiness=1、關閉透明大頁、啟用 HugePagesnet.core.somaxconnEXPLAIN 分析執行計劃 → 缺索引/全掃/臨時表/文件排序