類型系統差異
| # | 特性 | MySQL | SQL Server | 遷移要點 |
| 1 | 枚舉/集合 | ✅ ENUM, SET | ❌ 無 | 改用 CHECK 约束或查找表 |
| 2 | Unicode 類型 | ❌ 無 NCHAR/NVARCHAR | ✅ NCHAR, NVARCHAR, NTEXT | MySQL 用 CHARACTER SET utf8mb4 |
| 3 | 自增語法 | AUTO_INCREMENT | IDENTITY(1,1) | 種子/步長不同,MySQL 8.0+ 支持步長 |
| 4 | 默認值語法 | DEFAULT 0 | DEFAULT ((0)) | MySQL 不允許雙括號 |
| 5 | 存儲引擎 | ✅ 多引擎 (InnoDB, MyISAM...) | 單一引擎 | MySQL 建表必須指定 ENGINE |
| 6 | 標識符引用 | `反引號` | [方括號] | 遷移工具需自動轉換 |
| 7 | 當前時間 | NOW(), CURDATE(), CURTIME() | GETDATE() | MySQL 日期時間函數更豐富 |
| 8 | UPSERT | REPLACE INTO, INSERT ... ON DUPLICATE KEY UPDATE | MERGE (2008+) | 語法差異大,需逐條改寫 |
| 9 | 多值 INSERT | ✅ VALUES (...),(...) | ❌ 單值 (2008+ 支持 VALUES 行構造器) |
| 10 | 分頁語法 | LIMIT offset, count | TOP + 子查詢 / ROW_NUMBER() | **核心遷移難點** |
| 11 | 存儲引擎選擇 | 建表指定 | 無選擇 | |
| 12 | DATETIME 默認值 | ❌ 不支持 CURRENT_TIMESTAMP (5.6.5+ 支持) | ✅ DEFAULT GETDATE() | MySQL 用 TIMESTAMP 或觸發器 |
| 13 | DROP TABLE 安全 | DROP TABLE IF EXISTS | IF EXISTS + OBJECTPROPERTY | MySQL 極簡 |
| 14 | 無符號整數 | ✅ UNSIGNED | ❌ 無 | MySQL 多 1 倍正數範圍 |
| 15 | 大對象類型 | TEXT/BLOB 系列 | VARCHAR(MAX), VARBINARY(MAX) | SQL Server 統一大對象類型 |
| 16 | 索引創建 | KEY idx (col) | CREATE INDEX 完整語法 | |
| 17 | TEXT 默認值 | ❌ 不允許 | 允許 | |
| 18 | 行長度限制 | 65,535 字節 | 8,060 字節 (頁大小) | MySQL 更寬鬆 |
| 19 | 安裝體積 | ~200-300MB | ~4-6GB | MySQL 輕量化優勢明顯 |
| 20 | 管理工具 | Workbench, DBeaver, phpMyAdmin | SSMS (功能最強) | SSMS 體驗碾壓 MySQL 工具 |
| 21 | 存儲過程成熟度 | 較弱 (5.0+) | 極強 (T-SQL) | 複雜邏輯建議應用層實現 |
| 22 | 資源佔用 | 低 CPU/內存 | 高 | 同等負載 MySQL 更省資源 |
| 23 | PHP 連接 | mysqli, PDO | sqlsrv, PDO | PDO 統一介面遷移成本低 |
| 24 | 日期時間類型 | DATE, TIME, YEAR, DATETIME, TIMESTAMP | 2008 前僅 DATETIME/SMALLDATETIME | |
| 25 | JSON 支持 | 5.7+ 原生 JSON | 2016+ 原生 JSON | 功能相近,函數名不同 |
分頁查詢遷移實戰
MySQL LIMIT 語法
-- 前 10 條
SELECT * FROM users LIMIT 10;
-- 第 3 頁,每頁 10 條 (偏移 20,取 10)
SELECT * FROM users LIMIT 20, 10;
-- 或標準 SQL:2008
SELECT * FROM users LIMIT 10 OFFSET 20;
SQL Server 對應寫法
-- 前 10 條 (所有版本)
SELECT TOP 10 * FROM users;
-- 分頁:SQL Server 2012+ (推薦)
SELECT * FROM users
ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
-- 分頁:SQL Server 2005-2008 (經典子查詢法)
SELECT TOP 10 * FROM users
WHERE id NOT IN (
SELECT TOP 20 id FROM users ORDER BY id
) ORDER BY id;
-- 分頁:ROW_NUMBER() 通用法 (2005+)
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM users
) t WHERE rn BETWEEN 21 AND 30;
性能對比與優化
| 場景 | MySQL LIMIT | SQL Server OFFSET/FETCH | 優化建議 |
| 小偏移 (第 1-10 頁) | 極快 | 快 | 索引覆蓋 ORDER BY 列 |
| 大偏移 (第 10000 頁) | 慢 (掃描棄取) | 慢 (同樣掃描) | **游標分頁**:WHERE id > last_id LIMIT 10 |
| 無索引排序 | filesort | Sort 運算符 | 必須建立支持 ORDER BY 的索引 |
遷移工具鏈推薦
- Schema 轉換:
mysql-workbench 遷移向導、sqlines、DBConvert
- 數據同步:
pt-archiver、Canal (解析 Binlog)、Debezium
- 應用層適配:
PDO 統一數據庫介面,配合 Doctrine DBAL / SQLAlchemy ORM 抹平差異
遷移核心清單
- 類型映射:NVARCHAR → VARCHAR(utf8mb4), IDENTITY → AUTO_INCREMENT, GETDATE() → NOW()
- 語法重寫:TOP → LIMIT, MERGE → REPLACE/ON DUPLICATE KEY, 方括號 → 反引號
- 分頁重寫:OFFSET/FETCH → LIMIT, ROW_NUMBER() 子查詢 → LIMIT
- 存儲過程:T-SQL → MySQL Stored Procedure / 應用層代碼 (推薦)
- 事務隔離:READ COMMITTED (SQL Server 默認) vs REPEATABLE READ (MySQL 默認)
- 鎖提示:NOLOCK → 讀未提交 / 應用層容忍髒讀
- 測驗驗證:數據行數、檢查和、業務關鍵查詢結果一致性
總結
MySQL 與 SQL Server 差異本質是**「輕量級開源生態」vs「企業級閉源生態」**。遷移核心難點在於 **T-SQL 存儲過程重寫**、**分頁語法轉換**、**類型系統映射**。採用「Schema 先行、數據同步、應用雙寫、流量切換」四階段策略,配合 PDO/ORM 抽象層,可將遷移風險降至最低。