關係型資料庫的嚴格 Schema 在敏捷開發、快速迭代的業務場景下常成為瓶頸。FriendFeed 團隊曾分享一種「以 MySQL 實現 Schemaless」的創新架構:將物件序列化壓縮後存入單一 BLOB/VARBINARY 欄位,輔以獨立索引表支援查詢。本文深度解析此方案原理、實作細節與生產環境優化策略。
CREATE TABLE `blogs` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`object` VARBINARY(20000) NOT NULL COMMENT '序列化+壓縮後的物件',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
object 欄位存放 pickle.dumps(obj) → zlib.compress() 後的二進位資料。SELECT object FROM blogs WHERE id=? 極快,適合高頻單筆讀取。每個需查詢的欄位建立獨立索引表,不存放完整物件,僅存主鍵 ID 與索引欄位值:
-- 發文時間索引
CREATE TABLE `blog_idx_post_date` (
`id` INT(10) UNSIGNED NOT NULL,
`post_date` DATETIME NOT NULL,
PRIMARY KEY (`id`),
INDEX `idx_blogs_by_post_date` (`post_date`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 作者索引
CREATE TABLE `blog_idx_author` (
`id` INT(10) UNSIGNED NOT NULL,
`author` INT NOT NULL,
PRIMARY KEY (`id`),
INDEX `idx_blogs_by_author` (`author`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Blog(title=..., content=..., post_date=..., author=...)。blogs 主表 → 取得 auto_increment ID。(id, post_date)、(id, author)。| 查詢類型 | SQL 模式 | 適用場景 |
|---|---|---|
| 主鍵精確查詢 | SELECT object FROM blogs WHERE id=? | 單筆詳情、快取回填 |
| 單一索引範圍查詢 | SELECT id FROM blog_idx_post_date WHERE post_date BETWEEN ? AND ? → 回主表 | 時間軸列表、歸檔查詢 |
| 多條件組合查詢 | 各索引表取 ID 集合 → INTERSECT(應用層或 IN (SELECT...)) → 回主表 | 複雜篩選、後台管理 |
| 全文檢索 | 外部搜尋引擎 → 取 ID → 回主表 | 內容搜尋、模糊匹配 |
blogs 主表讀取後立即寫入 Redis(Key: blog:{id},TTL: 1h~24h)。測試顯示:快取命中率 > 95% 時,QPS 可提升 10-20 倍,且大幅降低 MySQL 連線壓力。
TRUNCATE + INSERT SELECT 重建索引表,修正漂移資料。VARBINARY(20000) 限制單物件 ~20KB。超過者:拆分至 blob_chunks 子表 或改用 LONGBLOB(需評估 InnoDB 行溢出影響)。zlib 平衡速度/壓縮率;lz4 / zstd 更快,適合高寫入場景。物件內嵌 __schema_version__ 欄位。讀取時由應用層 upgrader 負責舊版本資料轉換,實現「讀時遷移」,避免大鎖表操作。
| 維度 | MySQL Schemaless | MongoDB |
|---|---|---|
| 事務支援 | ✅ ACID 完整 | ✅ 4.0+ 多文件事務 |
| 成熟度/穩定性 | ✅ 極高 | ⚠️ 早期版本有資料丟失案例 |
| 運維成本 | ✅ 既有 MySQL 運維體系 | ⚠️ 額外技能樹、監控體系 |
| 查詢靈活度 | ⚠️ 需自建索引表 | ✅ 原生豐富查詢 |
| 水平擴展 | ⚠️ 需分庫分表/中間件 | ✅ 原生 Sharding |
結論: 若團隊深耕 MySQL 生態、業務以主鍵/單索引查詢為主、重視資料強一致與運維簡潔,MySQL Schemaless 是極具性價比的選擇;若需複雜多條件查詢、地理空間、原生水平擴展,MongoDB 更適合。
本方案在專案中已孵化穩定運行半年,核心元件將於春節後開源。歡迎同好交流、貢獻代碼,共同完善 MySQL Schemaless 生態。