analysis_sessions (百萬級行數)cid VARCHAR(50),建有普通索引 idx_cid (cid)mid-qqwanggou001- 的 cid 查詢變慢 **幾十倍**,普通 cid 查詢正常。EXPLAIN SELECT * FROM analysis_sessions WHERE cid = 'sid-a2f9047ddf528d837e5f60843c83aae9'; +----+-------------+-------------------+------+---------------+----------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------------+------+---------------+----------+---------+------+------+-------------+ | 1 | SIMPLE | analysis_sessions | ref | idx_cid | idx_cid | 27 | const| 1 | Using where | +----+-------------+-------------------+------+---------------+----------+---------+------+------+-------------+
rows=1 → 存儲引擎精準定位到 1 行,極快。cid VARCHAR(50),字符集 gbk (雙字節)。innodb_large_prefix、頁面大小影響,本案例實際索引長度為 **27 字節**。27 = 2(字節/字符) × 12(字符) + 2(長度前綴) + 1(NULL標誌) → **僅索引前 12 個字符**。SHOW INDEX FROM analysis_sessions WHERE Key_name='idx_cid'; +-------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | analysis_sessions | 1 | idx_cid | 1 | cid | A | 1650000| 12 | NULL | YES | BTREE | | | +-------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
Sub_part = 12 → **確認為前綴索引,長度 12 字符**。| 方案 | 操作 | 優點 | 缺點/風險 | 適用性 |
|---|---|---|---|---|
| 1. 重建索引指定長度 ≥ 17 | ALTER TABLE analysis_sessions DROP INDEX idx_cid, ADD INDEX idx_cid (cid(20)); | 精準命中、不改業務代碼 | 索引體積增大、重建鎖表 (Online DDL 5.6+ 緩解) | ✅ 首選 |
| 2. 遷移至 uuid/雪花 ID (無業務前綴) | 應用層生成無前綴 ID,cid 存純隨機串 | 根治前綴問題、索引高度選擇性最佳 | 需改造業務代碼、遷移存量數據 | ✅ 長期治本 |
| 3. 將前綴移至後綴 | cid = 'b99359d9054171901c0-mid-qqwanggou001' | 索引前綴區分度高、不改索引定義 | 需改造寫入/查詢邏輯、LIKE '%xxx' 仍無法用索引 | ⚠️ 次選 |
| 4. 強制全表掃描 (反模式) | SELECT * FROM analysis_sessions IGNORE INDEX(idx_cid) WHERE cid=... | 避免「局部全表掃描」的隨機 I/O,轉為順序掃描 | 全表掃描同樣慢、治標不治本 | ❌ 禁用 |
ADD INDEX idx_cid (cid(30)) 顯式指定長度覆蓋業務前綴,避免依賴默認前綴索引。innodb_large_prefix=ON (5.6.3+ 默認 ON) 可支持 3072 字節索引前綴。key_len 覆蓋業務區分度、rows=1 (或極小)、無 Using filesort/Using temporary。Innodb_rows_read 突增、Handler_read_rnd_next 異常 → 觸發慢查詢告警 → 自動 EXPLAIN 分析入庫。這次事故的核心教訓:**「索引被用上了」≠「索引用對了」**。
key_len是看穿前綴索引陷阱的「X 光」,Sub_part是確診書。
業務 ID 設計應**拒絕低區分度前綴**,索引定義應**顯式覆蓋業務區分度**,上線驗收應**讀懂 EXPLAIN 三大核心列**。
將這三條刻入團隊開發規範,才能從根源上杜絕「局部全表掃描」類性能事故。