Oracle 和mysql在SQL 语句上的的异同 (及Oracle在写SQL 语句时的注意事项)
以下是 Oracle 与 MySQL 在 SQL 语句上的核心差异对比及 Oracle 专属注意事项的详细解析:
一、SQL 语句核心差异对比
1. 分页查询
场景 | Oracle | MySQL |
---|---|---|
标准分页 | 需嵌套子查询+ROWNUM SELECT * FROM ( SELECT t.*, ROWNUM rn FROM table t WHERE ROWNUM <= 20 ) WHERE rn > 10 |
原生支持 LIMIT SELECT * FROM table LIMIT 10, 10 |
12c+新语法 | OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY |
- |
2. 日期处理
操作 | Oracle | MySQL |
---|---|---|
当前时间 | SYSDATE (含时间) CURRENT_DATE (会话时区) |
NOW() (含时间) CURDATE() (仅日期) |
日期计算 | 直接加减天数: SYSDATE + 1 (明天) |
需函数: DATE_ADD(NOW(), INTERVAL 1 DAY) |
格式化 | TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') |
DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') |
3. 字符串操作
功能 | Oracle | MySQL |
---|---|---|
连接 | `'str1' | |
空值处理 | NVL(col, 'default') |
IFNULL(col, 'default') |
正则匹配 | REGEXP_LIKE(col, 'pattern') |
col REGEXP 'pattern' |
4. 系统函数差异
函数 | Oracle | MySQL |
---|---|---|
类型转换 | TO_NUMBER('123') TO_DATE('2023-01-01', 'YYYY-MM-DD') |
CAST('123' AS SIGNED) STR_TO_DATE('2023-01-01', '%Y-%m-%d') |
序列生成 | CREATE SEQUENCE seq; SELECT seq.NEXTVAL FROM dual; |
AUTO_INCREMENT (表属性) |
伪表 | 必须 FROM dual SELECT 1+1 FROM dual; |
可省略 SELECT 1+1; |
二、Oracle SQL 专属注意事项
1. 性能陷阱规避
-
🚫 禁止隐式类型转换 :
索引列上的类型转换导致全表扫描
sql-- 错误(假设phone是字符串) SELECT * FROM users WHERE phone = 13800138000; -- 正确 SELECT * FROM users WHERE phone = '13800138000';
-
⚠️ 避免全表扫描操作符:
sql-- 慎用(导致索引失效) WHERE col IS NULL WHERE col NOT IN (...) WHERE col LIKE '%abc'
-
💡 绑定变量强制使用:
sql-- 错误(硬解析消耗CPU) SELECT * FROM orders WHERE order_id = 1001; -- 正确(绑定变量) SELECT * FROM orders WHERE order_id = :order_id;
2. 高级特性使用规范
-
分析函数优化统计:
sql-- 部门工资排名(避免自连接) SELECT name, salary, RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) dept_rank FROM employees;
-
MERGE 语句代替重复操作:
sqlMERGE INTO employees e USING (SELECT :id id, :name name FROM dual) new ON (e.id = new.id) WHEN MATCHED THEN UPDATE SET e.name = new.name WHEN NOT MATCHED THEN INSERT (id, name) VALUES (new.id, new.name);
3. 开发避坑指南
-
空字符串处理 :
Oracle 将
''
视为NULL
,需特殊处理:sql-- 错误(无结果) SELECT * FROM users WHERE name = ''; -- 正确 SELECT * FROM users WHERE name IS NULL;
-
事务控制分离 :
DML 语句必须显式提交:
sqlUPDATE accounts SET balance = balance - 100 WHERE id = 100; COMMIT; -- 必须显式提交
-
DDL 自动提交 :
CREATE/ALTER/DROP
语句执行后立即提交,无法回滚
三、跨数据库兼容方案
1. 分页查询兼容写法
sql
/* 通用分页模板 */
SELECT * FROM (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY id) rn
FROM table t
) WHERE rn BETWEEN :start AND :end
2. 日期处理兼容函数
sql
/* 三天后日期 */
-- Oracle
SELECT SYSDATE + 3 FROM dual;
-- MySQL
SELECT DATE_ADD(NOW(), INTERVAL 3 DAY);
-- 兼容方案(应用层计算)
3. 空值处理兼容
sql
/* 空值转默认值 */
-- Oracle
SELECT NVL(col, 0) FROM table;
-- MySQL
SELECT IFNULL(col, 0) FROM table;
-- 兼容方案
CREATE FUNCTION safe_null(val NUMBER, def NUMBER) RETURN NUMBER IS
BEGIN
RETURN COALESCE(val, def);
END;
四、Oracle 性能优化黄金法则
-
执行计划分析:
sqlEXPLAIN PLAN FOR SELECT * FROM large_table WHERE col = :value; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-
索引设计原则:
- 组合索引字段顺序:高选择性列在前
- 避免在索引列使用函数
- 位图索引仅适用于低基数列(<100个唯一值)
-
批量操作替代循环:
sql-- 错误(逐行提交) FOR i IN 1..1000 LOOP INSERT INTO log VALUES (...); COMMIT; END LOOP; -- 正确(批量提交) INSERT INTO log SELECT ... FROM bulk_table; COMMIT;
终极建议 :在 Oracle 中开发时,始终通过
DBMS_OUTPUT.PUT_LINE
打印执行耗时,对超过 100ms 的 SQL 必须进行执行计划分析。同时善用 AWR 报告定期进行系统级性能诊断。
通过掌握这些差异和注意事项,可显著提升 Oracle SQL 的开发效率和执行性能,避免踩坑。