首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

SQL 語句優化實戰:從 1 小時縮減至 5 分鐘的千萬級數據優化案例

     編輯:MySQL 綜合教學

SQL 語句優化實戰:從 1 小時縮減至 5 分鐘的千萬級數據優化案例

案例背景

  • 數據統計處理程序
  • 核心表達 千萬級 行
  • 涉及多表 JOIN、子查詢、聚合統計
  • 初始執行時間:~1 小時
  • 優化後:~5 分鐘 (提升 12 倍)

優化策略一:索引優化 (效果最顯著)

1. 缺失索引補齊

問題:CREATE TABLE ... AS SELECT 建表不會自動複製索引

-- 錯誤做法
CREATE TABLE tmp_stats AS SELECT * FROM big_table WHERE ...;

-- 正確做法:建表後立即加索引
CREATE TABLE tmp_stats AS SELECT * FROM big_table WHERE ...;
ALTER TABLE tmp_stats ADD INDEX idx_join_key (join_key);

2. 索引欄位選擇原則

  • JOIN 條件欄位:`ON a.id = b.id` → 兩側都需索引
  • WHERE 過濾欄位:高選擇性 (唯一值/總行數 > 0.1) 優先
  • GROUP BY / ORDER BY 欄位:避免 filesort
  • 覆蓋索引:`SELECT a,b FROM t WHERE c=1` → 索引 `(c,a,b)` 可索引掃描

3. 實測效果

單表 1000 萬行,無索引全表掃描 ~30 秒 → 加索引後 毫秒級

優化策略二:縮小查詢集合 (減少掃描行數)

1. 建立中間臨時表

-- 原始:直接查大表
SELECT ... FROM huge_table ht JOIN other o ON ht.id = o.id WHERE ht.status = 1;

-- 優化:先提取小集合
CREATE TEMPORARY TABLE tmp_ht AS
SELECT id, col1, col2 FROM huge_table WHERE status = 1; -- 從 1000萬 縮減至 50萬

-- 後續所有查詢針對 tmp_ht
SELECT ... FROM tmp_ht ht JOIN other o ON ht.id = o.id;

2. WHERE 條件順序優化

MySQL 優化器會自動重排,但複雜查詢時手動調整有幫助:

  • 將過濾率最高的條件放最前 (或最右,視優化器版本)
  • 使用 EXPLAIN 觀察 rows 估算行數變化

3. 子查詢優化

-- 低效:相關子查詢逐行執行
SELECT * FROM orders o WHERE o.user_id IN (SELECT id FROM users WHERE vip=1);

-- 高效:JOIN 或半連接
SELECT o.* FROM orders o JOIN users u ON o.user_id = u.id WHERE u.vip = 1;
-- 或 MySQL 8.0+ 半連接優化自動處理

優化策略三:去重優化

  • DISTINCT / GROUP BY 在大結果集上極耗資源
  • 若同一集合多次使用,先建去重臨時表,後續查詢直接用
  • 利用唯一索引隱性去重:`INSERT IGNORE INTO tmp_unique SELECT ...`

綜合優化清單

優化點工具/命令預期收益
補充缺失索引EXPLAIN、pt-index-usage★★★★★ (數量級)
拆分大查詢、建臨時表CREATE TEMPORARY TABLE★★★★☆
子查詢轉 JOINEXPLAIN select_type=DEPENDENT SUBQUERY★★★★☆
避免 SELECT *代碼審查★★★☆☆ (減少 I/O、網路)
分頁優化 (深分頁)延遲關聯/游標分頁★★★★☆
調整 JOIN 順序STRAIGHT_JOIN、小表驅動大表★★★☆☆
使用覆蓋索引EXPLAIN Extra=Using index★★★★☆

驗證方法論

  1. 基準測試:記錄優化前 QPS、延遲、掃描行數
  2. 單點變更:每次只調整一處,觀察變化
  3. EXPLAIN 對比:關注 type (all→ref→eq_ref)、rows、Extra
  4. 生產灰度:先在從庫/測試庫驗證,再上主庫

避坑指南

  • ❌ 盲目加索引:寫入效能下降、磁碟膨脹、優化器選錯索引
  • ❌ 過早優化:未定位瓶頸就重寫 SQL
  • ❌ 忽略統計資訊:`ANALYZE TABLE` 更新統計資訊,優化器才能做對決策
  • ✅ 建立 SQL 審核流程 (開發階段攔截)
  • ✅ 使用 pt-query-digest 分析慢查詢日誌
  • ✅ 定期 ANALYZE TABLE 或啟用 innodb_stats_persistent=ON

核心心法

「索引是銀彈,但不是萬能藥;縮小掃描範圍才是優化的本質。」

千萬級數據下,先加對索引,再縮小集合,最後才是調整 SQL 寫法。本案例 12 倍提升中,索引貢獻 ~70%,臨時表貢獻 ~20%,SQL 重寫 ~10%。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved