SELECT COUNT(*) FROM task
WHERE status=2 AND operator_id=20839
AND operate_time>1371169729 AND operate_time<1371174603
AND type=2;
開發建議「給每個字段加索引」,實則應建聯合索引並遵循最左前綴原則,將範圍列 operate_time 放最後,且需綜合評估所有相關查詢確定最佳列順序。
(a,b,c) 按順序建樹,查詢必須從最左列開始匹配,遇到範圍查詢 (>,<,>=,<=,LIKE) 停止匹配後續列。a=1 AND b=2 AND c>3 AND d=4 → 索引 (a,b,c,d) 中 d 無法用到;調整為 (a,b,d,c) 則全部生效。count(DISTINCT col)/count(*) > 0.1 (JOIN 字段建議)。低區分度列 (性別/狀態) 不宜建索引。from_unixtime(create_time) = '...' 失效,改為 create_time = unix_timestamp('...')。(a) 需 (a,b) 直接修改原索引。SQL_NO_CACHE) 確認確實慢。EXPLAIN 定位驅動表 (返回行數最少的表優先)。EXPLAIN 驗證執行計劃是否符合預期 (從小表驅動)。ORDER BY ... LIMIT 讓排序表優先查。原 SQL:cm_log JOIN 子查詢 (employee LEFT JOIN emp_certificate) 含 OR 條件,產生臨時表 + join buffer,掃描 6 萬行,耗時 1.87s。
優化:拆分為兩個 UNION (去重) / UNION ALL (不去重) 子查詢,各自簡單 JOIN,利用現有索引,耗時 10ms。
SQL:WHERE accurate_result=1 AND sync_status IN (0,2,4),兩列區分度極低 (各 3 個值),理論不建索引。
業務場景:每 5 分鐘掃描處理,處理後將 sync_status 改為 1,符合條件行極少 (~1000)。
優化:建立 INDEX (accurate_result, sync_status),業務保證的數據傾斜使索引極高效,6.22s → 200ms。
SQL:4 表 JOIN 後 ORDER BY c.created_time DESC LIMIT 10,執行計劃 rows 很小但實際排序 77 萬行,13s。
嘗試優化:改為 EXISTS 子查詢 + 主表排序,參數正常時 0.00s,但極端參數 (內層無匹配) 導致 MySQL 反覆取 10 行嘗試 JOIN,耗時 2 分 18 秒 (比原 SQL 更差)。
結論:並非所有 SQL 可優化,極端場景下優化可能適得其反,需業務層面解決 (如分頁改為游標、增加過濾條件)。
「查詢容易,優化不易,且寫且珍惜!」
數據庫層面優化永遠抵不上應用架構優化。同樣的 MySQL,能支撐 Google/Taobao,也可能撐不起個人站點。