同一個業務場景——手機產品庫(基本屬性 + 動態參數),在 MySQL 與 MongoDB 中呈現截然不同的建模哲學。本文通過完整 DDL/DSL 對比、查詢語句對比、索引策略對比、遷移決策矩陣,幫您建立「關係思維 → 文檔思維」的轉換框架。
CREATE TABLE `mobiles` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(100) NOT NULL,
`brand` VARCHAR(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `mobile_params` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`mobile_id` INT UNSIGNED NOT NULL,
`param_name` VARCHAR(100) NOT NULL,
`param_value` VARCHAR(100) NOT NULL, -- 統一存字串,數值需 CAST
INDEX `idx_mobile_id` (`mobile_id`),
INDEX `idx_name_value` (`param_name`, `param_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `mobiles` (`id`,`name`,`brand`) VALUES
(1,'ME525','摩托羅拉'), (2,'E7','諾基亞');
INSERT INTO `mobile_params` (`mobile_id`,`param_name`,`param_value`) VALUES
(1,'待機時間','200'), (1,'外觀設計','直板'),
(2,'待機時間','500'), (2,'外觀設計','滑蓋');
-- 步驟 1:找出符合條件的 mobile_id
SELECT mobile_id FROM mobile_params
WHERE (param_name='待機時間' AND CAST(param_value AS UNSIGNED) > 100)
OR (param_name='外觀設計' AND param_value='直板')
GROUP BY mobile_id
HAVING COUNT(DISTINCT param_name) = 2; -- 同時滿足兩個條件
-- 步驟 2:回主表查基本資料
SELECT * FROM mobiles WHERE id IN (上述結果);
痛點:EAV (Entity-Attribute-Value) 模型導致型別喪失、索引效率低、查詢複雜、JOIN 開銷大。
// 集合:mobiles
{
_id: 1,
name: "ME525",
brand: "摩托羅拉",
params: [
{ name: "待機時間", value: 200 }, // 數值型別保留
{ name: "外觀設計", value: "直板" }
]
}
{
_id: 2,
name: "E7",
brand: "諾基亞",
params: [
{ name: "待機時間", value: 500 },
{ name: "外觀設計", value: "滑蓋" }
]
}
db.mobiles.createIndex({ "params.name": 1, "params.value": 1 });
// 多鍵索引:陣列中每個元素獨立建立索引項
// 支援 $elemMatch 精準匹配陣列內單一元素的多欄位條件
db.mobiles.find({
params: {
$all: [
{ $elemMatch: { name: "待機時間", value: { $gt: 100 } } },
{ $elemMatch: { name: "外觀設計", value: "直板" } }
]
}
});
優勢:單集合、單查詢、型別保真、索引精準命中、無 JOIN。
| 維度 | MySQL (EAV) | MongoDB (文檔嵌入) |
|---|---|---|
| 資料模型 | 正規化、分表、外鍵關聯 | 反正規化、嵌入陣列/子文檔、聚合根 |
| 動態屬性 | 新增行、統一 VARCHAR、型別轉換 | 直接新增欄位/陣列元素、原生型別 |
| 查詢複雜度 | 多表 JOIN、子查詢、GROUP BY HAVING | 單集合、$elemMatch/$all、聚合管道 |
| 索引機制 | B+ 樹單值/複合、覆蓋索引 | 多鍵索引、複合多鍵、部分索引、TTL 索引 |
| 事務邊界 | 跨表 ACID、行鎖 | 單文檔 ACID、4.0+ 多文檔事務 |
| Schema 演進 | DDL 鎖表、遷移腳本 | 無 Schema、應用層兼容、驗證規則可選 |
| 擴展性 | 垂直分表、水平分片 (中間件) | 原生分片、自動平衡、區域分片 |
| 特徵 | 傾向 MySQL | 傾向 MongoDB |
|---|---|---|
| 資料結構 | 穩定、關係緊密、強一致性需求 | 多變、半結構化、屬性稀疏 |
| 查詢模式 | 複雜多表 JOIN、OLAP、報表 | 單實體存取、鍵值/文檔查詢、地理空間 |
| 寫入模式 | 事務性多表寫入 | 高併發單文檔寫入、日誌/事件溯源 |
| 團隊技能 | SQL 強、關係建模經驗豐富 | JSON/文檔思維、敏捷迭代 |
| 運維成本 | 成熟工具鏈、DBA 熟悉 | 需投入學習、監控體系不同 |
[寫入服務] → MySQL (主記錄、事務、強一致)
↓ Binlog CDC (Canal/Debezium)
[讀取/搜尋服務] → MongoDB (文檔視圖、全文檢索、彈性查詢)
↓ 同步
[分析服務] → ClickHouse / Doris (OLAP)
find()、aggregate() 實際過濾/排序欄位建立複合/多鍵索引從「表、行、外鍵、JOIN」到「集合、文檔、嵌入、$elemMatch」,這不僅是語法遷移,更是領域建模哲學的升維。掌握文檔思維,您將能為高併發、快速迭代、多樣化查詢的現代應用,設計出更自然、更高效的資料架構。下一篇我們將探討 MySQL 連線池空閒超時 (wait_timeout) 與 DBCP/HikariCP 協同調優實戰,敬請期待。