單表百萬行、幾十萬活躍用戶,對 MySQL 來說屬於「輕量級」負載。若查詢慢、CPU 高、鎖等待頻發,多半是 SQL 寫法、索引設計或架構層面有問題。本文彙整 30 條經過生產驗證的優化鐵律,涵蓋 SQL 改寫、索引策略、架構模式、PHP 代碼層面,助你從「能跑」進化到「跑得快、穩得住」。
WHERE、ORDER BY、JOIN ON 涉及的列必須建索引。IS NULL 判斷:WHERE num IS NULL 導致全掃 → 改 DEFAULT 0 + WHERE num=0。!=/<>:同樣放棄索引 → 改用 UNION ALL 分段查詢。OR 連接條件:num=10 OR num=20 → UNION ALL 兩條 num=10 / num=20。IN/NOT IN:連續值用 BETWEEN;大列表改 EXISTS 或臨時表 JOIN。LIKE '%abc%':全掃 → 上全文索引或 Elasticsearch。WHERE num=@num 編譯時未知值 → 強制索引 FORCE INDEX(idx) 或改為預處理綁定參數。num/2=100 → num=200;SUBSTRING(name,1,3)='abc' → name LIKE 'abc%';DATEDIFF(day, dt, '2023-01-01')=0 → dt >= '2023-01-01' AND dt < '2023-01-02'。= 左側做表達式:同第 8 條,破壞 SARGable(可索引搜尋論)。INDEX(a,b,c) 查詢必帶 a,且順序最好一致。SELECT * FROM t WHERE 1=0 建空表 → 用 CREATE TABLE ... LIKE t。EXISTS 替代 IN(子查詢):SELECT * FROM a WHERE EXISTS (SELECT 1 FROM b WHERE b.num=a.num),半連接優化、避免物化子查詢。SELECT a,b FROM t WHERE c=? → INDEX(c,a,b),EXPLAIN 顯示 Using index,零回表。VARCHAR 代替 CHAR:變長省空間、查詢掃描少字節。SELECT *:只取需要列,減少網路傳輸、緩存污染、覆蓋索引機會增大。DECLARE @t TABLE(...)(僅主鍵索引),大數據慎用。SELECT INTO #tmp(少 Log、快);小量 → CREATE TABLE #tmp + INSERT(緩解系統表鎖)。TRUNCATE #tmp; DROP TABLE #tmp,避免系統表長時間鎖定。FAST_FORWARD 游標可接受(只讀、單向、無並發)。SET NOCOUNT ON(存儲過程首尾):減少 DONE_IN_PROC 網路往返。mysqli::persistent(慎用,注意連接數上限)。$stmt = $mysqli->prepare(...) 防注入 + 執行計劃複用。SELECT 到 Slave,降低 Master 壓力。pt-query-digest 分析慢查詢、Prometheus + Grafana 監控 QPS/延遲/鎖等待/複製延遲。百萬級數據優化,核心是「讓索引生效、讓事務變短、讓架構分層」。30 條鐵律不是死規矩,而是「遇到慢查詢先檢查哪幾條」的檢查清單。養成 EXPLAIN 先行、SHOW PROFILE 定位、pt-query-digest 定期巡檢的習慣,PHP + MySQL 系統才能在業務增長中保持穩健。