MySQL数据库系统学习笔记(3)
Oracle与MySQL一般性对比
只做大概性的罗列性质的大致化整理,后续部分有代码对比实例,仅做参考,请以更全面具体的专业性文章和手册为准
一、基础架构差异
1. 数据库架构
Oracle:
- 采用”实例-数据库”的多租户架构
- 一个实例可管理多个PDB(可插拔数据库)
- 共享内存区域(SGA)设计复杂精细
MySQL:
- 简单直接的”实例-数据库”架构
- 默认存储引擎InnoDB采用表空间管理
- 缓冲池(Buffer Pool)是主要内存区域
2. 存储引擎
Oracle:
- 单一存储引擎架构
- 自动管理所有数据存储细节
MySQL:
- 插件式存储引擎(InnoDB/MyISAM等)
- 不同引擎特性差异大(如事务支持、锁机制)
二、数据类型差异
1. 数值类型
类型 | Oracle | MySQL |
---|---|---|
整数 | NUMBER(10) | INT/BIGINT |
小数 | NUMBER(10,2) | DECIMAL(10,2) |
浮点数 | BINARY_FLOAT | FLOAT/DOUBLE |
2. 字符串类型
类型 | Oracle | MySQL |
---|---|---|
定长字符串 | CHAR(10) | CHAR(10) |
变长字符串 | VARCHAR2(4000) | VARCHAR(65535) |
大文本 | CLOB | LONGTEXT |
三、SQL语法差异
1. 分页查询
Oracle:1
2
3
4SELECT * FROM (
SELECT t.*, ROWNUM rn FROM employees t
WHERE ROWNUM <= 20
) WHERE rn > 10;
MySQL:1
SELECT * FROM employees LIMIT 10, 10;
2. 日期处理
Oracle:1
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM dual;
MySQL:1
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
四、事务与锁机制
1. 事务隔离级别
隔离级别 | Oracle支持 | MySQL支持 |
---|---|---|
READ UNCOMMITTED | ❌ | ✅ |
READ COMMITTED | ✅(默认) | ✅ |
REPEATABLE READ | ✅ | ✅(默认) |
SERIALIZABLE | ✅ | ✅ |
2. 锁机制
Oracle:
- 行级锁为主
- 自动升级锁粒度
- 支持多版本读一致性
MySQL(InnoDB):
- 行级锁+间隙锁
- 不自动升级锁粒度
- MVCC实现机制不同
五、高可用方案
Oracle高可用
- RAC (Real Application Clusters)
- Data Guard
- GoldenGate
MySQL高可用
- 主从复制
- Group Replication
- InnoDB Cluster
- MHA (Master High Availability)
六、备份恢复机制
Oracle备份
- RMAN (Recovery Manager)
- 支持块级别增量备份
- 时间点恢复精确到秒
MySQL备份
- mysqldump逻辑备份
- Percona XtraBackup物理备份
- 二进制日志(binlog)恢复
七、性能优化差异
Oracle优化
- 复杂的执行计划管理
- 丰富的统计信息收集
- SQL Tuning Advisor
MySQL优化
- EXPLAIN分析执行计划
- 慢查询日志分析
- 索引优化简单直接
八、适用场景建议
选择Oracle当:
- 企业级关键业务系统
- 需要复杂分析处理
- 极高可用性要求
- 大数据量高并发场景
选择MySQL当:
- Web应用/互联网服务
- 快速迭代开发项目
- 中小规模数据量
- 成本敏感型项目
九、迁移注意事项
- 数据类型转换:特别注意NUMBER与DECIMAL的精度处理
- SQL重写:分页、序列、日期函数等语法差异
- 事务处理:隔离级别和锁行为的差异
- 性能调优:执行计划和索引策略需要重新评估
十、未来发展趋势
Oracle:
- 继续强化云服务(Oracle Cloud)
- 自动化运维方向
- 多模型数据库支持
MySQL:
- 增强分析处理能力
- 改进Group Replication
- 更好的云原生支持
Oracle与MySQL常用语法对照手册
一、分页查询语法对比
1. 标准分页实现
Oracle (12c以下版本):1
2
3
4
5
6
7
8
9
10-- 传统ROWNUM三层嵌套写法
SELECT *
FROM (
SELECT t.*, ROWNUM AS rn
FROM (
SELECT * FROM employees ORDER BY hire_date
) t
WHERE ROWNUM <= 20 -- 结束行
)
WHERE rn > 10; -- 起始行
MySQL:1
2
3
4-- 简洁的LIMIT语法
SELECT * FROM employees
ORDER BY hire_date
LIMIT 10, 10; -- 起始行, 行数
2. 12c+ Oracle新分页语法
1 | -- 12c开始支持的FETCH语法 |
二、序列操作对比
1. 创建序列
Oracle:1
2
3
4
5
6CREATE SEQUENCE emp_seq
START WITH 100
INCREMENT BY 1
MAXVALUE 999999
NOCYCLE
CACHE 20;
MySQL (AUTO_INCREMENT):1
2
3
4
5CREATE TABLE employees (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100),
PRIMARY KEY (id)
) AUTO_INCREMENT = 100;
2. 获取序列值
Oracle:1
2
3
4
5-- 获取下一个值
SELECT emp_seq.NEXTVAL FROM dual;
-- 获取当前值
SELECT emp_seq.CURRVAL FROM dual;
MySQL:1
2
3-- 插入后获取最后ID
INSERT INTO employees (name) VALUES ('张三');
SELECT LAST_INSERT_ID();
三、日期处理对比
1. 当前时间获取
Oracle:1
2SELECT SYSDATE FROM dual; -- 系统日期
SELECT CURRENT_TIMESTAMP FROM dual; -- 时间戳
MySQL:1
2
3SELECT NOW(); -- 当前日期时间
SELECT CURDATE(); -- 当前日期
SELECT CURTIME(); -- 当前时间
2. 日期格式化
Oracle:1
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM dual;
MySQL:1
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
四、字符串处理对比
1. 字符串连接
Oracle:1
2
3SELECT first_name || ' ' || last_name AS full_name FROM employees;
-- 或者使用CONCAT函数(只支持两个参数)
SELECT CONCAT(first_name, CONCAT(' ', last_name)) FROM employees;
MySQL:1
2SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM employees;
-- 或者使用更简洁的||(在ANSI模式下)
2. 子字符串提取
Oracle:1
SELECT SUBSTR('Oracle', 2, 3) FROM dual; -- 输出'rac'
MySQL:1
2
3SELECT SUBSTRING('MySQL', 2, 3); -- 输出'ySQ'
-- 或者简写
SELECT SUBSTR('MySQL', 2, 3);
五、条件表达式对比
1. CASE表达式
Oracle:1
2
3
4
5
6
7
8SELECT
employee_name,
CASE
WHEN salary > 10000 THEN '高级'
WHEN salary > 5000 THEN '中级'
ELSE '初级'
END AS level
FROM employees;
MySQL (语法相同):1
2
3
4
5
6
7
8SELECT
employee_name,
CASE
WHEN salary > 10000 THEN '高级'
WHEN salary > 5000 THEN '中级'
ELSE '初级'
END AS level
FROM employees;
2. 特有函数
Oracle特有:1
2
3
4
5-- NVL空值处理
SELECT NVL(commission_pct, 0) FROM employees;
-- DECODE函数
SELECT DECODE(gender, 'M', '男', 'F', '女', '其他') FROM employees;
MySQL特有:1
2
3
4
5-- IFNULL空值处理
SELECT IFNULL(commission_pct, 0) FROM employees;
-- IF函数
SELECT IF(salary > 5000, '高薪', '普通') FROM employees;
六、分析函数对比
1. 行号生成
Oracle:1
2
3
4
5SELECT
employee_name,
salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS rank
FROM employees;
MySQL (8.0+):1
2
3
4
5SELECT
employee_name,
salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS rank
FROM employees;
2. 分组排名
Oracle:1
2
3
4
5
6SELECT
department_id,
employee_name,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank
FROM employees;
MySQL (8.0+):1
2
3
4
5
6SELECT
department_id,
employee_name,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank
FROM employees;
七、临时表对比
1. 创建临时表
Oracle:1
2
3
4
5
6
7
8
9
10
11-- 事务级临时表
CREATE GLOBAL TEMPORARY TABLE temp_emp (
emp_id NUMBER,
emp_name VARCHAR2(100)
) ON COMMIT DELETE ROWS;
-- 会话级临时表
CREATE GLOBAL TEMPORARY TABLE temp_emp_session (
emp_id NUMBER,
emp_name VARCHAR2(100)
) ON COMMIT PRESERVE ROWS;
MySQL:1
2
3
4
5-- 会话级临时表
CREATE TEMPORARY TABLE temp_emp (
emp_id INT,
emp_name VARCHAR(100)
);
八、事务控制对比
1. 事务语法
Oracle:1
2
3
4
5
6
7-- 默认每个DML语句就是一个事务(自动提交)
-- 显式事务
SET TRANSACTION READ WRITE;
INSERT INTO accounts VALUES (...);
COMMIT;
-- 或者
ROLLBACK;
MySQL:1
2
3
4
5
6
7-- 默认自动提交
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION;
INSERT INTO accounts VALUES (...);
COMMIT;
-- 或者
ROLLBACK;
九、存储过程对比
1. 基本结构
Oracle:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15CREATE OR REPLACE PROCEDURE raise_salary (
p_emp_id IN NUMBER,
p_amount IN NUMBER
) AS
BEGIN
UPDATE employees
SET salary = salary + p_amount
WHERE employee_id = p_emp_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END;
MySQL:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20DELIMITER //
CREATE PROCEDURE raise_salary (
IN p_emp_id INT,
IN p_amount DECIMAL(10,2)
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
UPDATE employees
SET salary = salary + p_amount
WHERE employee_id = p_emp_id;
COMMIT;
END //
DELIMITER ;
这篇技术手册详细对比了Oracle和MySQL在关键语法上的差异,特别是重点展示了分页查询的不同实现方式。实际开发中,这些语法差异是数据库迁移或跨数据库开发时需要特别注意的要点。。
Oracle与MySQL面试问答示例
问题1:请说明Oracle和MySQL在分页查询实现上的主要区别?
面试者回答:
“在分页查询方面,Oracle和MySQL有显著不同的实现方式:
MySQL使用非常简洁的LIMIT语法:
1
SELECT * FROM products ORDER BY price DESC LIMIT 20, 10;
这表示跳过20条取10条,执行效率很高。
Oracle 11g及以下版本需要使用三层嵌套ROWNUM:
1
2
3
4
5SELECT * FROM (
SELECT t.*, ROWNUM rn FROM (
SELECT * FROM products ORDER BY price DESC
) t WHERE ROWNUM <= 30
) WHERE rn > 20;这种写法比较复杂,但12c版本开始支持了更简单的FETCH语法:
1
2
3SELECT * FROM products
ORDER BY price DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
实际项目中,MySQL的分页写法更受开发者欢迎,但在处理超大数据量分页时,两种数据库都需要特别注意性能优化。”
问题2:Oracle的NUMBER类型和MySQL的数值类型如何对应?
面试者回答:
“在数值类型存储方面,我有这样的理解:
Oracle的NUMBER类型是个”万能”类型,通过指定精度可以表示各种数值:
NUMBER(10)
对应MySQL的INT
NUMBER(10,2)
对应MySQL的DECIMAL(10,2)
但需要注意几个关键差异:
- Oracle NUMBER默认能存38位精度,而MySQL的DECIMAL最大支持65位
- Oracle的NUMBER(5)和NUMBER(5,0)是不同的,前者可能存储小数
- 在迁移数据库时,特别要注意NUMBER不带精度的情况,需要评估实际数据范围
在我的上一个项目中,我们就遇到过Oracle的NUMBER(10)迁移到MySQL时,因为实际数据超出INT范围而不得不改用BIGINT的情况。”
问题3:解释下Oracle和MySQL事务隔离级别的实现差异?
面试者回答:
“这个问题涉及到两个数据库的核心设计理念:
- Oracle默认使用READ COMMITTED隔离级别,通过多版本并发控制(MVCC)实现:
- 查询只能看到已提交的数据
- 使用回滚段(Undo Segment)维护数据旧版本
- 读操作不会阻塞写操作
- MySQL(InnoDB)默认使用REPEATABLE READ,但通过独特的MVCC实现:
- 每个事务有自己的一致性视图
- 通过ReadView和undo log实现
- 通过间隙锁(Gap Lock)防止幻读
一个重要的实践差异是:在Oracle中,同一个事务内多次查询可能看到不同结果(不可重复读),而MySQL可以保证重复读结果一致。这在我们电商系统的库存控制中非常重要,MySQL的默认隔离级别更适合需要强一致性的场景。”
问题4:如果要从Oracle迁移到MySQL,你会重点关注哪些方面?
面试者回答:
“根据我的迁移经验,会重点关注以下方面:
- SQL语法改写:
- 分页查询的重写
- 序列(Sequence)改为AUTO_INCREMENT
- 日期函数转换(如SYSDATE→NOW())
- 数据类型映射:
- VARCHAR2→VARCHAR
- NUMBER→合适的数值类型
- CLOB→LONGTEXT
- 事务处理:
- 隔离级别差异的影响评估
- 锁机制差异导致的并发问题
- 性能优化:
- 执行计划差异分析
- 索引策略调整
- 参数配置优化
在我们最近的人力资源系统迁移项目中,就遇到了Oracle的复杂分析函数在MySQL中性能较差的问题,最终通过业务逻辑拆分和查询重写解决了。我的经验是先做小规模POC验证,再制定详细的迁移检查清单。”
以上内容仅做参考示例,一切以实际项目为准。