Sphinx 同步幾萬行數據卻跑 4-5 分鐘,EXPLAIN 顯示索引正常,SHOW PROCESSLIST 長期卡在 Sending data。本文通過 SHOW PROFILE 定位到 VARCHAR(8000) 大字段,揭示 InnoDB COMPACT 行格式下溢出頁不入緩衝池的機制。
description VARCHAR(8000) 的表EXPLAIN:索引正常,首表全掃描(業務必需)SHOW PROCESSLIST:長期 Sending dataSHOW PROFILE:Sending data 耗時 216 秒


| 查詢 | 耗時 | 倍數 |
|---|---|---|
| 不返回 description | 15 秒 | 1x |
| 返回 description | 216 秒 | 14.4x |

COMPACT/REDUNDANT 行格式:
- 行內存前 768 字節
- 超出部分存入 溢出頁(Uncompressed BLOB 頁)
- 讀取需「主頁 → 溢出頁」雙重查找,變順序讀為隨機讀
關鍵發現:SHOW TABLE STATUS 顯示平均行長 1.5KB,約 1/10 行用溢出頁。

更關鍵:**溢出頁不進入 Buffer Pool**。反覆執行同一查詢、甚至全表掃描,速度不變,證明溢出頁每次都從磁盤讀取。設計邏輯:防止大對象沖刷熱點頁。
| 方案 | 優點 | 缺點 | 適用性 |
|---|---|---|---|
| 1. 查詢不選大字段 | 零改動、立竿見影 | 業務可能強制需要 | ✅ 首選 |
| 2. 垂直拆表 | 主表變窄、索引緩存命中率升 | 改動大、若仍頻繁 JOIN 大字段表收益有限 | ✅ 徹底治本 |
| 3. 改用 DYNAMIC/COMPRESSED 行格式 | 大字段全外置、主頁更緊湊 | 需重建表、溢出頁仍不緩存 | ⚠️ 輔助 |
| 4. 外部存儲(對象存儲/文件系统) | DB 極瘦、海量大對象友好 | 架構複雜、一致性需應用層保證 | ✅ 架構級方案 |
ALTER TABLE ... ROW_FORMAT=DYNAMIC 重建(需停機或 pt-online-schema-change)SELECT id, col1, col2 避免 SELECT *Innodb_buffer_pool_pages_flushed、Innodb_data_reads 飆升