如果你熟悉 MySQL,学习 Oracle 最大的障碍在于架构哲学的不同。MySQL 追求简单直观,Oracle 追求严谨和企业级管控。
以下是用 MySQL 的概念来类比讲解 Oracle 的核心概念:
1. 实例与数据库 (Instance vs Database)
| 概念 | MySQL | Oracle | 核心区别 |
|---|---|---|---|
| 实例 | 进程 + 内存 (mysqld) | 进程 + 内存 (SGA/PGA) | 类似 |
| 数据库 | 数据文件集合 (data dir) | 数据文件集合 (data files) | 类似 |
| 关系 | 通常视为一体 | 严格分离 | ⚠️ 最大区别 |
- MySQL :启动
mysqld服务,就能访问数据文件。通常说"启动数据库"就是指启动服务。 - Oracle :
- 实例 (Instance):内存结构 + 后台进程(相当于发动机)。
- 数据库 (Database):磁盘上的文件(相当于车身)。
- 关系:实例可以挂载(Mount)和打开(Open)数据库。
- 影响:Oracle 可以重启实例而不删除数据文件;RAC 架构下多个实例可以同时打开一个数据库。
sql
-- MySQL: 启动服务即可用
service mysql start
-- Oracle: 需要启动实例并打开数据库
sqlplus / as sysdba
startup -- 启动实例 + 挂载 + 打开数据库
2. 用户与模式 (User vs Schema) ⭐⭐⭐
这是 MySQL 用户最不适应的地方。
| 概念 | MySQL | Oracle | 核心区别 |
|---|---|---|---|
| 数据库 | CREATE DATABASE db1 |
无直接对应 | MySQL 的 DB ≈ Oracle 的 Schema |
| 用户 | CREATE USER 'u1'@'%' |
CREATE USER u1 |
类似 |
| 模式 | DATABASE 即 SCHEMA |
用户即模式 | ⚠️ 绑定关系 |
| 对象归属 | 表属于数据库 (db1.table) |
表属于用户 (u1.table) |
命名空间不同 |
- MySQL :
- 创建数据库
db1。 - 创建用户
u1。 - 授权
u1访问db1。 - 用户和数据库是分离的。
- 创建数据库
- Oracle :
- 创建用户即创建模式 :
CREATE USER u1会自动创建一个名为u1的 Schema。 - 对象归属 :
u1创建的表自动属于u1模式。 - 访问方式 :其他用户访问需加前缀
SELECT * FROM u1.table_name。 - 没有"数据库"概念:整个实例就是一个大数据库,通过 Schema 隔离数据。
- 创建用户即创建模式 :
sql
-- MySQL: 切换数据库
USE db1;
SELECT * FROM table1;
-- Oracle: 切换用户 (类似切换数据库)
CONNECT u1/password;
SELECT * FROM table1; -- 实际是 u1.table1
-- Oracle: 跨用户访问
SELECT * FROM u1.table1; -- 需要授权
3. 表空间 (Tablespace)
| 概念 | MySQL (InnoDB) | Oracle | 核心区别 |
|---|---|---|---|
| 逻辑容器 | DATABASE |
TABLESPACE | Oracle 多了一层抽象 |
| 物理文件 | .ibd 或 ibdata1 |
.dbf (Data File) |
类似 |
| 管理粒度 | 每表一个文件或共享 | 表空间管理多个段 | Oracle 更灵活 |
- MySQL :表直接属于数据库,数据存在
.ibd文件中。 - Oracle :表属于 表空间 ,表空间对应多个 数据文件 。
- 层级:
数据库 → 表空间 → 段 (表) → 区 → 块。 - 好处:可以移动表空间文件而不影响逻辑结构,便于存储管理。
- 层级:
sql
-- MySQL: 建表指定存储引擎
CREATE TABLE t1 (id INT) ENGINE=InnoDB;
-- Oracle: 建表指定表空间
CREATE TABLE t1 (id NUMBER) TABLESPACE users;
4. 命名空间 (Namespace) ⭐
| 概念 | MySQL | Oracle | 核心区别 |
|---|---|---|---|
| 对象重名 | 表、视图、存储过程可同名 | 表、视图、过程不可同名 | ⚠️ 冲突规则 |
| 范围 | 数据库内唯一 | 用户 (Schema) 内唯一 | 类似 |
- MySQL :在同一个库中,可以有一个表叫
test,同时有一个存储过程也叫test。 - Oracle :在同一个用户(Schema)下,表、视图、序列、存储过程共享命名空间 。
- 如果有表
EMP,就不能创建视图EMP或过程EMP。 - 索引有独立的命名空间(可以和表同名,但不建议)。
- 如果有表
sql
-- MySQL: ✅ 允许
CREATE TABLE test (id INT);
CREATE PROCEDURE test() BEGIN END;
-- Oracle: ❌ 报错 ORA-00955
CREATE TABLE test (id NUMBER);
CREATE VIEW test AS SELECT * FROM dual; -- 名称已由现有对象使用
5. 自增主键 (Auto Increment)
| 概念 | MySQL | Oracle (12c 前) | Oracle (12c 后) |
|---|---|---|---|
| 语法 | AUTO_INCREMENT |
序列 (Sequence) | Identity 列 |
| 实现 | 表属性 | 独立对象 | 表属性 (类似 MySQL) |
| 灵活性 | 每表独立 | 序列可多表共享 | 每表独立 |
- MySQL :直接在列上定义
AUTO_INCREMENT。 - Oracle (传统) :需要创建独立的
SEQUENCE对象,然后在插入时调用seq.NEXTVAL。 - Oracle (12c+) :支持
IDENTITY列,语法接近 MySQL。
sql
-- MySQL
CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY);
-- Oracle (12c 之前)
CREATE SEQUENCE t_seq;
INSERT INTO t VALUES (t_seq.NEXTVAL);
-- Oracle (12c 之后)
CREATE TABLE t (id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY);
6. 空值处理 (NULL Handling) ⚠️
| 概念 | MySQL | Oracle | 核心区别 |
|---|---|---|---|
| 空字符串 | '' != NULL |
'' = NULL |
⚠️ 重大差异 |
| 长度 | LENGTH('') = 0 |
LENGTH('') = NULL |
逻辑不同 |
| 索引 | 空字符串可索引 | NULL 不被普通索引存储 | 影响查询优化 |
- MySQL:空字符串是有效的值,不等于 NULL。
- Oracle :空字符串自动转换为 NULL 。
- 影响:
WHERE col = ''在 Oracle 中永远查不到数据(应使用IS NULL)。 - 影响:唯一索引允许多个 NULL 值(因为 NULL != NULL)。
- 影响:
sql
-- MySQL
SELECT * FROM t WHERE col = ''; -- 能查到空字符串
-- Oracle
SELECT * FROM t WHERE col = ''; -- 查不到 (被当作 NULL)
SELECT * FROM t WHERE col IS NULL; -- 才能查到
7. 大小写敏感 (Case Sensitivity)
| 概念 | MySQL | Oracle | 核心区别 |
|---|---|---|---|
| 表名 | Linux 敏感,Windows 不敏感 | 默认不敏感 (转大写) | 存储方式不同 |
| 标识符 | 保持原样 | 未加引号自动转大写 | ⚠️ 易踩坑 |
| 字符串 | 取决于 Collation | 取决于比较设置 | 类似 |
- MySQL :
CREATE TABLE MyTab,查询时SELECT * FROM MyTab或mytab(取决于配置)。 - Oracle :
CREATE TABLE MyTab→ 内部存储为MYTAB。SELECT * FROM MyTab→ 自动转大写查询MYTAB。SELECT * FROM "MyTab"→ 加引号区分大小写 ,内部存储为MyTab(后续查询必须加引号)。- 建议 :Oracle 中永远不要给对象名加双引号,统一大写。
sql
-- Oracle: 推荐写法
CREATE TABLE employees; -- 存储为 EMPLOYEES
SELECT * FROM employees; -- 自动转大写,成功
-- Oracle: 不推荐写法
CREATE TABLE "employees"; -- 存储为 employees (小写)
SELECT * FROM employees; -- 报错 (找 EMPLOYEES)
SELECT * FROM "employees"; -- 成功 (必须加引号)
8. 事务与 DDL (Transaction & DDL)
| 概念 | MySQL | Oracle | 核心区别 |
|---|---|---|---|
| DML 提交 | 默认自动提交 (autocommit=1) | 默认不自动提交 | 需手动 COMMIT |
| DDL 提交 | 隐式提交 | 隐式提交 | 类似 |
| 回滚 | 可回滚 DML | DDL 不可回滚 | 类似 |
- MySQL :默认
autocommit=1,每条 SQL 立即生效。 - Oracle :默认
autocommit=0。INSERT/UPDATE/DELETE后必须显式COMMIT否则其他会话不可见。CREATE/ALTER/DROP会自动提交当前事务(无法回滚 DDL)。
sql
-- Oracle 脚本习惯
UPDATE employees SET salary = 10000;
-- 此时数据未提交,其他会话看不到
COMMIT; -- 必须显式提交
DROP TABLE temp; -- 执行前会自动 COMMIT 之前的未提交事务
9. 总结对比表
| 特性 | MySQL | Oracle | 迁移/学习建议 |
|---|---|---|---|
| 隔离单元 | Database (库) | Schema (用户) | 把 Oracle 用户当 MySQL 库用 |
| 对象命名 | 表/过程可同名 | 表/过程不可同名 | 命名时加前缀 (PKG_, V_) |
| 空字符串 | '' 是值 |
'' 是 NULL |
代码中避免判空串,用 IS NULL |
| 大小写 | 依赖操作系统 | 默认大写 | 对象名不要加双引号 |
| 自增 | AUTO_INCREMENT |
Sequence / Identity | 12c 后用 Identity,之前用序列 |
| 分页 | LIMIT offset, size |
ROWNUM / OFFSET FETCH |
12c 后用 OFFSET FETCH |
| 提交 | 默认自动提交 | 手动 COMMIT | 脚本末尾记得加 COMMIT |
| 函数 | IFNULL, NOW() |
NVL, SYSDATE |
记忆常用函数对应关系 |
10. 给 MySQL 开发者的 Oracle 速记口诀
- 用户即库:Oracle 里没有"库",创建一个用户就当创建了一个库。
- 大写优先:对象名别加引号,Oracle 会自动转大写。
- 空串即空 :别判断
col = '',要判断col IS NULL。 - 手动提交 :写完
UPDATE别忘了COMMIT,否则数据"消失"了。 - DDL 提交:建表删表会自动提交,之前的修改别想回滚。
- 命名冲突:表名别和视图、存储过程重名。
- 分页写法 :12c 以前用
ROWNUM,12c 以后用OFFSET FETCH。 - 双引号禁忌 :除非必须小写,否则永远别用
"name",只用name。