MySQL 長期運行後,索引統計資訊過期、資料碎片累積、頁面損壞等問題會嚴重影響效能與資料完整性。MySQL 提供 ANALYZE、OPTIMIZE、CHECK、REPAIR、CHECKSUM 五大維護語句,本文系統解析其原理、適用場景、執行策略與自動化建議,助您建立標準化資料庫維護體系。
重新掃描表頁面,更新 Cardinality (基數)——即索引欄位的不重複值數量。優化器依賴此統計資訊判斷索引選擇性,Cardinality 嚴重偏離實際值會導致優化器誤判,放棄索引改走全表掃描。
INSERT/UPDATE/DELETE 後 (建議變更超過 10% 時)。SHOW INDEX 顯示 Cardinality 與實際不重複值差距大。ref 變為 ALL。-- 基本用法
ANALYZE TABLE players;
-- 不寫入 Binlog (避免主從同步延遲、備份膨脹)
ANALYZE LOCAL TABLE players;
-- 批次分析多表
ANALYZE TABLE t1, t2, t3;
SHOW INDEX FROM players;
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| players| 0 | PRIMARY | 1 | playerno | A | 1000 | NULL | NULL | | BTREE | | |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
-- Cardinality 從 14 更新為 1000,索引恢復有效
針對 MyISAM、InnoDB、ARCHIVE 引擎:
ANALYZE TABLE 更新統計資訊。DELETE 或 UPDATE 變長欄位 (VARCHAR/TEXT/BLOB) 的表。SHOW TABLE STATUS 顯示 Data_free 偏大 (超過資料大小 20%)。OPTIMIZE TABLE orders;
OPTIMIZE LOCAL TABLE orders; -- 不寫 Binlog
-- InnoDB 實際執行邏輯等同於:
ALTER TABLE orders ENGINE=InnoDB; -- 重建表
ANALYZE TABLE orders; -- 更新統計
鎖表警告:OPTIMIZE 期間會持有排他鎖,阻塞所有讀寫。大表 (超過 10GB) 執行時間可能達數小時,生產環境必須在低峰期或使用 pt-online-schema-change 類工具線上重建。
CHECKSUM=1 建表選項)。| 模式 | 速度 | 檢查深度 | 適用場景 |
|---|---|---|---|
QUICK | 最快 | 僅檢查索引樹結構,不掃描資料列連結 | 日常巡檢、大表快速掃描 |
FAST | 極快 | 僅檢查表是否正常關閉 (標記) | 掉電重啟後快速確認 |
CHANGED | 快 | 僅檢查上次檢查後有變更的表 | 增量巡檢 |
MEDIUM (預設) | 中等 | 掃描索引連結、驗證資料列刪除標記、計算校驗和 | 常規維護、疑似損壞初步排查 |
EXTENDED | 最慢 | 全表掃描、逐行驗證所有鍵值、完整校驗和 | 嚴重損壞深度診斷、資料完整性審計 |
UPGRADE | 中等 | 檢查舊版建表是否相容當前版本 | 版本升級後必跑 |
CHECK TABLE players MEDIUM;
-- 結果欄位說明
+-----------------+-----+----------+----------+
| Table | Op | Msg_type | Msg_text |
+-----------------+-----+----------+----------+
| tennis.players | check| status | OK | -- 正常
| tennis.players | check| error | Corrupt | -- 損壞,需 REPAIR
| tennis.players | check| warning | ... | -- 警告,如統計資訊過期
+-----------------+-----+----------+----------+
SELECT TABLE_NAME, CHECK_TIME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'tennis' AND TABLE_NAME = 'players';
關鍵限制:僅支援 MyISAM、ARCHIVE、CSV 引擎。InnoDB 損壞需透過 innodb_force_recovery 或從備份恢復。
| 模式 | 速度 | 修復深度 | 風險 |
|---|---|---|---|
QUICK | 最快 | 僅重建索引樹 (.MYI),不動資料檔 | 低,但若資料檔損壞則無效 |
EXTENDED | 最慢 | 逐行讀取資料檔重建索引,嘗試恢復最大資料量 | 可能丟失損壞行,耗時極長 |
USE_FRM | 中等 | .MYI 遺失時,依 .frm 結構重建完整索引 | 需確認 .frm 完好 |
REPAIR TABLE players QUICK;
REPAIR LOCAL TABLE players EXTENDED; -- 不寫 Binlog
計算表資料的 CRC32 校驗和。MyISAM 若建表指定 CHECKSUM=1,會維護即時校驗和 (Live Checksum),寫入時自動更新。
CHECKSUM TABLE players; -- 預設 EXTENDED,重新計算
CHECKSUM TABLE players QUICK; -- 直接讀取儲存的 Live Checksum (極快)
# crontab -e (mysql 用戶)
# 每日 02:30 快速檢查核心表
30 2 * * * mysql -e "CHECK TABLE core_db.orders, core_db.users FAST;" >> /var/log/mysql_check.log 2>&1
# 每週日 03:00 中等深度檢查 + 碎片評估
0 3 * * 0 /usr/local/bin/mysql_maintenance.sh --medium --analyze >> /var/log/mysql_maint.log 2>&1
# 每月 01 號 04:00 優化高碎片表 (Data_free > 20%)
0 4 1 * * /usr/local/bin/mysql_optimize.sh --threshold=20 >> /var/log/mysql_optimize.log 2>&1
#!/bin/bash
THRESHOLD=20
mysql -NBe "SELECT TABLE_SCHEMA, TABLE_NAME, DATA_FREE, DATA_LENGTH+INDEX_LENGTH AS total_size
FROM INFORMATION_SCHEMA.TABLES
WHERE ENGINE='InnoDB' AND DATA_FREE > 0 AND TABLE_SCHEMA NOT IN ('mysql','sys','performance_schema','information_schema')
HAVING (DATA_FREE / total_size) * 100 > $THRESHOLD" |
while read db table free total; do
echo "[$(date)] OPTIMIZE $db.$table (fragment: $((free*100/total))%)"
mysql -e "OPTIMIZE LOCAL TABLE \`$db\`.\`$table\`;"
done
| 語句 | 核心功能 | 支援引擎 | 鎖定行為 | 建議頻率 | 關鍵參數 |
|---|---|---|---|---|---|
| ANALYZE | 更新統計資訊 | 所有 | 讀鎖 (短) | 每日/大量變更後 | LOCAL (不寫 Binlog) |
| OPTIMIZE | 重建表、消除碎片 | MyISAM, InnoDB, ARCHIVE | 排他鎖 (長) | 每週/碎片>20% | LOCAL, 低峰期執行 |
| CHECK | 檢測損壞 | 所有 | 讀鎖 | 每日 QUICK, 每週 MEDIUM | QUICK/MEDIUM/EXTENDED |
| REPAIR | 修復損壞 | MyISAM, ARCHIVE, CSV | 排他鎖 | 檢測到損壞時 | QUICK/EXTENDED/USE_FRM |
| CHECKSUM | 一致性校驗 | MyISAM (Live), 所有 (計算) | 讀鎖 | 備份前後/主從對比 | QUICK (讀取 Live) |
pt-online-schema-change、gh-ost 或 MySQL 8.0 INSTANT DDL 避免長時間鎖表。sql_log_bin=0 (需 SUPER 權限)。innodb_force_recovery=1..6 導出資料重建,或從備份恢復。innodb_stats_persistent_sample_pages (預設 20) 或 innodb_stats_transient_sample_pages (預設 8)。