mcpField
O
oracle-to-mariadb

oracle-to-mariadb

github.com/mariadb数据与数据库1782 次安装2 周前更新
代码仓库

关于 oracle-to-mariadb

oracle-to-mariadb 是为计划或执行 Oracle 数据库迁移到 MariaDB 的团队编写的参考 Skill。它介绍 Oracle 兼容模式、数据类型映射、需手动改写的内容和迁移工具,并说明版本相关注意事项。

主要功能

  1. 01说明 Oracle 兼容模式
  2. 02列出 Oracle 到 MariaDB 的类型映射
  3. 03指出需要手动改写的语法
  4. 04汇总迁移工具和版本注意事项

适用场景

  1. 01迁移前评估 Oracle 架构兼容性
  2. 02规划不支持 SQL 结构的改写
  3. 03检查数据类型与事务行为差异

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mariadb/skills --skill oracle-to-mariadb

安装后在 Claude Code 中输入/oracle-to-mariadb确认已加载。

详细介绍

Oracle 到 MariaDB 迁移指南

最后更新:2026-06-04

为什么选择 MariaDB 进行 Oracle 迁移

MariaDB 是唯一原生兼容 PL/SQL 的开源数据库。MySQL 没有与 Oracle 兼容模式相当的功能。PostgreSQL 则需要彻底重写 PL/SQL。MariaDB 的 sql_mode=ORACLE 可让约 80% 的 Oracle 代码无需修改即可运行,包括存储过程、程序包、游标、异常处理和 Oracle 风格函数。

相较于其他开源替代方案,MariaDB 还有以下优势:

  • Connect 存储引擎——迁移期间通过 ODBC 联合查询实时 Oracle 数据,无需完全切换
  • 系统版本控制表——可用于时态数据,与 Oracle Flashback Archive 相匹配;这是开源数据库中独有的功能
  • ColumnStore——列式分析引擎,可与 Oracle 的 In-Memory ColumnStore 相媲美
  • 成本:组织通常可将 Oracle 许可成本降低 70–90%

**要求:**使用 MariaDB Community Server 10.3+ 才能启用 Oracle 兼容模式。使用 10.6+ 才能支持 ROWNUM、TO_CHAR()、ADD_MONTHS()、SYS_GUID()。当前 LTS 版本为 11.8(2025 年 5 月)。

第一步:启用 Oracle 兼容模式

SET sql_mode = 'ORACLE';
-- or permanently in configuration:
-- sql_mode = ORACLE

如果不启用此模式,PL/SQL 语法、Oracle 数据类型同义词和 Oracle 风格函数都无法使用。这是最重要的一步,也是最常被遗漏的一步。

LLM 容易出错的地方

你可能看到的内容正确做法
PL/SQL 因语法错误而无法运行先设置 sql_mode=ORACLE——否则无法识别 PL/SQL 结构
将 Oracle DATE 映射为 MariaDB DATEOracle DATE 同时存储日期和时间——应映射为 DATETIME,而非 DATE
认为 PL/SQL 兼容率为 100%约 80% 的代码可直接运行;SYNONYM、INSERT ALL 和 CONNECT BY 通常需要重写——12.1+ 的 Oracle 模式支持 (+) 连接(见下一行)
在架构或代码中使用 SYNONYMMariaDB 没有等效功能——应替换为视图或直接引用对象
(+) 外连接表示法MariaDB 12.1 起的 Oracle 模式支持此表示法(MDEV-13817)——旧版本应重写为 LEFT JOIN / RIGHT JOIN
START WITH ... CONNECT BY不支持——应使用 WITH RECURSIVE 重写为递归 CTE
TIMESTAMP WITH TIME ZONE迁移时会丢失时区信息——将变为 DATETIME;应在应用程序中处理时区

数据类型映射

sql_mode=ORACLE 会自动处理以下类型:

OracleMariaDB说明
VARCHAR2(n)VARCHAR(n)自动
NUMBER(p,s)DECIMAL(p,s)自动
NUMBERDOUBLE自动
DATEDATETIME**自动,但请注意:**Oracle DATE 包含时间;MariaDB DATE 不包含时间
CLOBLONGTEXT自动
BLOBLONGBLOB自动
RAW(n)VARBINARY(n)自动
CHAR(n > 255)VARCHAR(n)手动
TIMESTAMP WITH TIME ZONEDATETIME手动——时区信息会丢失
BFILELONGBLOB手动——文件路径的存储方式不同
ROWIDCHAR(10)手动

sql_mode=ORACLE 的覆盖范围

PL/SQL 语法(10.3+)
  • 包:CREATE PACKAGE、CREATE PACKAGE BODY — 从 11.4 起,也可在 sql_mode=ORACLE 之外使用(MDEV-10075),因此可在混合模式代码库中使用包
  • 游标:显式、隐式、带参数、%ISOPEN、%ROWCOUNT、%FOUND、%NOTFOUND
  • 用于预处理语句的游标(12.3+)
  • 游标变量:TYPE ... IS REF CURSOR(13.0+)— 将游标作为过程参数传递并作为返回值返回
  • 预定义的弱类型 SYS_REFCURSOR(12.0+)— 内置游标类型,无需 TYPE 声明;系统变量 max_open_cursors 限制可同时打开的游标数量
  • 变量类型::= 赋值、%TYPE、%ROWTYPE
  • 将 ROW 数据类型用作存储函数的返回值(11.7+)— 函数返回结构化行,类似 Oracle 行类型
  • 在例程参数和函数 RETURN 子句中使用 RECORD 类型(13.0+)
  • 关联数组:DECLARE TYPE ... TABLE OF ... INDEX BY(12.1+)
  • 存储例程参数可设默认值(11.8+)— 像 Oracle 的 DEFAULT 子句一样,使用较少的参数调用过程
  • 控制流:FOR i IN 1..10 LOOP、GOTO、EXIT WHEN、ELSIF、CONTINUE
  • 异常处理:EXCEPTION WHEN TOO_MANY_ROWS / NO_DATA_FOUND / DUP_VAL_ON_INDEX
  • 匿名块:BEGIN ... END
  • 动态 SQL:EXECUTE IMMEDIATE ... USING
  • 触发器变量::NEW、:OLD
Oracle 兼容函数
函数起始支持版本
DECODE()10.3
CHR()、位置为 0 的 SUBSTR()10.3
ADD_MONTHS()10.6
TO_CHAR()10.6(12.0 添加了用于抑制填充的 FM 格式)
SYS_GUID()10.6
ROWNUM10.6
TO_NUMBER()12.2.1
TO_DATE()12.3(原生支持;旧版本请使用 STR_TO_DATE())
TRUNC()12.2
NULL 处理

Oracle 将空字符串视为 NULL。sql_mode=ORACLE 不会自动启用此行为 — 必须另行添加 EMPTY_STRING_IS_NULL:

SET sql_mode = 'ORACLE,EMPTY_STRING_IS_NULL';

如果未启用 EMPTY_STRING_IS_NULL,即使在 Oracle 模式下,MariaDB 中的 '' 也不是 NULL。

其他自动行为
  • 将 || 用作字符串拼接运算符(忽略 NULL)
  • MINUS 作为 EXCEPT 的同义词(10.6+)
  • 预处理语句中的命名占位符(:1、:2)
  • SELECT UNIQUE 作为 SELECT DISTINCT 的同义词
  • 支持 DUAL 表

需要手动改写的内容

以下 Oracle 功能没有直接对应项,需要修改代码:

  • SYNONYM — 替换为视图(CREATE VIEW)或直接更新对象引用
  • INSERT ALL / INSERT FIRST — 改写为多条 INSERT 语句或应用逻辑
  • (+) 外连接语法 — 从 MariaDB 12.1 起,在 Oracle 模式下原生支持。旧版本请改写为 LEFT JOIN / RIGHT JOIN:
    -- Oracle:
    SELECT * FROM a, b WHERE a.id = b.id(+);
    -- MariaDB:
    SELECT * FROM a LEFT JOIN b ON a.id = b.id;
    
  • START WITH ... CONNECT BY — 改写为递归 CTE:
    -- MariaDB equivalent:
    WITH RECURSIVE tree AS (
        SELECT id, parent_id, name FROM categories WHERE parent_id IS NULL
        UNION ALL
        SELECT c.id, c.parent_id, c.name FROM categories c
        JOIN tree t ON c.parent_id = t.id
    )
    SELECT * FROM tree;
    
  • TIMESTAMP WITH TIME ZONE — 将时区偏移量存储在单独的列中,或在应用中处理
  • 对象类型和继承 — 没有对应实现;请重新设计为规范化表

迁移工具

  • MariaDB Migration Assessment Tool — 分析 Oracle DDL 导出并评估兼容性,助你在开始迁移前了解准备情况
  • Connect Storage Engine — 创建可通过 ODBC 读取实时 Oracle 数据的 MariaDB 表;适用于无需一次性完全切换的分阶段迁移
  • DBeaver — 在 Oracle 和 MariaDB 之间进行架构映射、数据比较和传输
  • MaxScale 查询改写 — 对无法在应用中更改的情况,实时拦截并改写不受支持的 Oracle 语法

关键注意事项

  • 自动提交(提交模型相反):Oracle 没有 autocommit 变量,默认使用手动提交——INSERT/UPDATE/DELETE 操作在显式运行 COMMIT 之前不会持久化。MariaDB 则相反:默认情况下,autocommit 为 ON,因此每条语句都会立即提交。要保留 Oracle 的批量操作后再提交的行为,请将工作单元包装在 START TRANSACTION ... COMMIT 中,或设置 autocommit=0。请参阅 Oracle 的事务概念指南。
  • SYSDATE:在 MariaDB Oracle 模式下,SYSDATE 可用,但返回 DATETIME。请验证仅比较日期的操作。
  • DUAL:在 MariaDB 中可用,但行为并不完全相同——避免使用 schema.DUAL 这类带架构限定的引用。
  • 序列:MariaDB 10.3+ 支持使用与 Oracle 兼容的语法(MINVALUE、MAXVALUE、INCREMENT BY)运行 CREATE SEQUENCE。
  • 存在活动会话时执行 DROP USER(12.1+):行为与 Oracle 兼容——在 Oracle 模式下,如果用户存在活动会话,DROP USER 会失败;在其他模式下,则会发出警告。
  • 约 20% 需要重写:没有任何工具能够实现 100% 的 Oracle 到 MariaDB 转换。请预留时间,手动检查复杂的 PL/SQL、对象类型和不受支持的语法。

来源

对于此处未涵盖的主题,请参阅 MariaDB 官方文档:mariadb.com/docs。

评论

支持 Markdown