將 Oracle 開發的應用系統移植至 MySQL,是降低授權成本、適應客戶既有環境的常見需求。但兩者在 SQL 語法、資料型別、大小寫敏感度、保留字、自動遞增、索引限制等方面存在顯著差異。本文系統梳理遷移過程中的核心坑點與解決方案,並提出資料庫相容性設計原則,助您平滑遷移。
| Oracle | MySQL (Linux) |
|---|---|
| 不區分大小寫(無雙引號時) | 資料庫/表名區分大小寫(對應目錄/檔案) |
| 工具匯出腳本通常轉大寫 | 欄位名預設不區分,但建議一致 |
解決方案:
- 統一資料庫/表名大小寫(建議全小寫)
- 應用程式 SQL 中表名、欄位名大小寫與資料庫定義完全一致
- 若應用 SQL 大小寫混亂,需全面修正或使用 lower_case_table_names=1(需重啟、有副作用)
Oracle 允許保留字作表名/欄位名;MySQL 會報語法錯誤(如 interval、show)。
解決方案:
- 反引號包裹:INSERT INTO t (id, \`interval\`) VALUES (...)
- 或加表名前綴:INSERT INTO t (id, t.interval) VALUES (...)
- 根治:遷移腳本階段系統性重命名衝突識別字
| Oracle | MySQL | 備註 |
|---|---|---|
| VARCHAR2(n) | VARCHAR(n) | 語義相同 |
| NUMBER(p,s) | DECIMAL(p,s) / NUMERIC(p,s) | MySQL 無 NUMBER |
| DATE | DATETIME / TIMESTAMP | Oracle DATE 含時間 |
| CLOB | LONGTEXT | |
| BLOB | LONGBLOB | |
| — | TIME | MySQL 獨有,Oracle 無對應 |
| Oracle | MySQL |
|---|---|
| SEQUENCE 物件 | AUTO_INCREMENT 欄位屬性 |
需手動 seq.NEXTVAL | INSERT 時自動填充 |
解決方案:
- 將 SEQUENCE 改為 AUTO_INCREMENT 主鍵
- 複雜場景:建立專用序號表模擬 SEQUENCE
解決方案:縮減索引欄位長度、使用前綴索引 INDEX(name(50))、調整字符集為 utf8mb4(4 bytes/字元,更嚴格)
\` 反引號(Oracle 不支援)DUAL、SYSDATE、ROWNUM 等LIMIT、PostgreSQL OFFSET/LIMIT、Oracle ROWNUM/ROW_NUMBER() → 統一由持久層框架處理hibernate.globally_quoted_identifiers 等_table_name、_id(但影響可讀性,建議改用業務前綴如 usr_、ord_)||、MySQL CONCAT()、標準 || (MySQL 需 SQL_MODE=PIPES_AS_CONCAT)NVL/COALESCE、IFNULL → 統一用 COALESCE (標準)MySQL Workbench Migration Wizard、Ora2Pg、自研腳本DataX、Canal、Kettle、sqlldr + LOAD DATA INFILE| 症狀 | 可能原因 | 對策 |
|---|---|---|
| 查詢極慢 | 索引未建立、統計資訊缺失、執行計畫差異 | ANALYZE TABLE、優化 SQL、調整 innodb_buffer_pool_size |
| 資料截斷 | VARCHAR 長度不足、字符集編碼差異 | 擴大欄位、統一 utf8mb4 |
| 主鍵衝突 | AUTO_INCREMENT 起始值、序號表未同步 | ALTER TABLE ... AUTO_INCREMENT=... |
| 事務行為異常 | MySQL 預設 REPEATABLE READ、Oracle READ COMMITTED | 明確設定隔離級別、檢查鎖等待 |
Oracle 到 MySQL 的遷移,技術上可行但細節決定成敗。核心策略是:源頭設計相容性、遷移期工具自動化、驗證期全量回歸。若新專案預見多資料庫部署,請在架構初期引入抽象持久層、統一命名規範、標準 SQL 寫法,將遷移成本壓縮至最低。對於存量系統,建議分階段遷移:唯讀服務先行、核心交易最後、雙寫過渡、流量漸進切換,確保業務零中斷。