在高併發寫入場景下,盲目添加二級索引往往因維護成本導致寫入效能雪崩。本文通過一個消息表的真實優化案例,展示如何通過結構重構、業務邏輯下沉,在不增加任何新索引的前提下,將百萬級數據查詢從 4.75 秒降至 0.0001 秒,實現讀寫效能的雙贏。
原表結構:
CREATE TABLE chat_message (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
content TEXT,
user_id BIGINT,
is_wonderful TINYINT, -- 是否精彩發言
is_top TINYINT, -- 是否置頂
is_barrage TINYINT -- 是否彈幕
);
業務需頻繁查詢「精彩發言」「置頂消息」「彈幕消息」。數據量達 37 萬時,全表掃描耗時 4.75 秒。雖加索引可降至 0.1 秒,但每新增一個索引,寫入延遲明顯上升;三個業務欄位若全建索引,高頻寫入場景下將嚴重拖慢吞吐。
InnoDB 聚簇索引特性決定:主鍵索引葉子節點直接存放完整行數據,二級索引葉子節點僅存主鍵值,查詢需「回表」。若能將篩選條件轉化為主鍵範圍掃描,即可繞過二級索引,直接利用聚簇索引有序性實現極速查詢。
步驟 1:抽離業務屬性,建立映射表
CREATE TABLE message_type_ref (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
type TINYINT NOT NULL COMMENT '1-精彩 2-置頂 3-彈幕',
chat_message_id BIGINT NOT NULL,
INDEX idx_type (type) -- 僅此一個輔助索引
);
步驟 2:查詢邏輯轉換
SELECT * FROM chat_message WHERE is_wonderful = 1(全表掃描/二級索引回表)SELECT cm.* FROM chat_message cm JOIN message_type_ref mtr ON cm.id = mtr.chat_message_id WHERE mtr.type = 1映射表 idx_type 快速定位符合類型的主鍵 ID,再回主表按主鍵批量查詢。因主鍵有序,InnoDB 可執行高效的 Range Scan,且無額外回表開銷。
| 指標 | 原方案(全表掃描) | 加三個二級索引 | 重構方案(映射表) |
|---|---|---|---|
| 查詢耗時 (37 萬行) | 4.753 秒 | ~0.1 秒 | 0.0001 秒 |
| 寫入影響 | 基準 | 每索引 +5~15% 延遲 | 僅維護 1 張小表索引,影響可忽略 |
| 索引維護成本 | 0 | 3 個二級索引 | 1 個小表索引 |
| 存儲開銷 | 基準 | +3 × 索引大小 | + 映射表 (極小) |
EXPLAIN SELECT cm.* FROM chat_message cm JOIN message_type_ref mtr ON cm.id = mtr.chat_message_id WHERE mtr.type = 1; +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+ | 1 | SIMPLE | mtr | NULL | ref | idx_type | idx_type | 1 | const | 100 | 100.00 | Using index | | 1 | SIMPLE | cm | NULL | eq_ref | PRIMARY | PRIMARY | 8 | mtr.chat_message_id | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
映射表走 ref 類型命中 idx_type,主表走 eq_ref 直接命中 PRIMARY,零回表、零臨時表、零文件排序。
此模式適用於「標籤/狀態/分類」等低基數屬性頻繁篩選的高寫入表,是「以空間換時間、以結構換索引」的經典實踐。