Oracle SQL 开发规范

Oracle SQL 开发规范

适用版本:Oracle Database 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

SQL 开发规范保证代码质量[1]:

详细见:Oracle 数据库设计原则详解


2. 命名规范

2.1 表

- 单数
- 业务前缀
- 下划线
- < 30 字符
- 示例:emp_employee, ord_order

2.2 列

- 清晰
- 类型后缀(可选)
- 主键:id
- 外键:xxx_id
- 名称:name, title
- 日期:xxx_date
- 金额:xxx_amount
- 状态:status

2.3 对象

类型前缀示例
-employees
视图v_v_emp_dept
序列seq_seq_emp
索引idx_idx_emp_name
主键pk_pk_employees
唯一uk_uk_emp_email
外键fk_fk_emp_dept
检查ck_ck_emp_salary
非空nn_nn_emp_name
过程sp_sp_hire_emp
函数fn_fn_get_count
pkg_pkg_emp
触发器trg_trg_audit_emp
类型t_ / ty_t_emp_rec
异常e_e_invalid_salary
常量c_c_max_salary
变量v_v_count
参数p_p_dept_id

3. SQL 风格

3.1 关键字大写

SELECT id, name, salary
FROM employees
WHERE dept_id = 10
ORDER BY name;

3.2 缩进

SELECT 
    e.id,
    e.name,
    d.dept_name
FROM employees e
    INNER JOIN departments d ON e.dept_id = d.id
WHERE e.status = 'ACTIVE'
    AND e.salary > 5000
ORDER BY e.name;

3.3 列对齐

SELECT e.id,
       e.name,
       e.salary
FROM   employees e
WHERE  e.dept_id = 10;

3.4 别名

SELECT e.id AS employee_id,
       e.name AS employee_name
FROM employees e
JOIN departments d ON e.dept_id = d.id;

4. SELECT

4.1 明确列

-- 好
SELECT id, name, salary FROM employees WHERE id = 100;

-- 差
SELECT * FROM employees WHERE id = 100;

4.2 别名

SELECT e.id AS employee_id,
       d.dept_name AS department
FROM employees e, departments d
WHERE e.dept_id = d.id;

5. WHERE

5.1 索引友好

-- 好
SELECT * FROM employees WHERE id = 100;
SELECT * FROM employees WHERE name = 'Alice';

-- 差(函数)
SELECT * FROM employees WHERE UPPER(name) = 'ALICE';

-- 差(计算)
SELECT * FROM employees WHERE salary / 12 > 5000;

-- 好
SELECT * FROM employees WHERE salary > 60000;

5.2 类型匹配

-- 好
SELECT * FROM employees WHERE id = 100;
SELECT * FROM employees WHERE name = 'Alice';

-- 差(隐式转换)
SELECT * FROM employees WHERE id = '100';
SELECT * FROM employees WHERE hire_date = '2025-01-01';

详细见:Oracle SQL 查询优化技巧


6. JOIN

6.1 现代语法

-- 好
SELECT e.name, d.dept_name
FROM employees e
  INNER JOIN departments d ON e.dept_id = d.id
WHERE e.status = 'ACTIVE';

-- 老式(不推荐)
SELECT e.name, d.dept_name
FROM employees e, departments d
WHERE e.dept_id = d.id AND e.status = 'ACTIVE';

6.2 表别名

SELECT e.name, d.dept_name
FROM employees e
  JOIN departments d ON e.dept_id = d.id;

详细见:Oracle JOIN 连接方式


7. 绑定变量

7.1 PL/SQL

-- 自动绑定
CREATE PROCEDURE get_emp(p_id NUMBER) IS
  v_name employees.name%TYPE;
BEGIN
  SELECT name INTO v_name FROM employees WHERE id = p_id;
END;

7.2 动态 SQL

-- 好
EXECUTE IMMEDIATE 'SELECT * FROM t WHERE id = :id' USING v_id;

-- 差
EXECUTE IMMEDIATE 'SELECT * FROM t WHERE id = ' || v_id;

7.3 应用

// 好
PreparedStatement ps = con.prepareStatement("SELECT * FROM emp WHERE id = ?");
ps.setInt(1, 100);

// 差
String sql = "SELECT * FROM emp WHERE id = " + 100;

详细见:Oracle PL/SQL 动态 SQL 详解


8. PL/SQL

8.1 命名

CREATE OR REPLACE PROCEDURE sp_hire_emp(
  p_name IN VARCHAR2,
  p_salary IN NUMBER DEFAULT 5000,
  p_dept_id IN NUMBER,
  p_emp_id OUT NUMBER
) IS
  v_count NUMBER;
  c_max_salary CONSTANT NUMBER := 100000;
BEGIN
  ...
EXCEPTION
  WHEN OTHERS THEN
    ...
END;
/

8.2 异常处理

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- 具体处理
  WHEN TOO_MANY_ROWS THEN
    -- 具体处理
  WHEN OTHERS THEN
    log_error(...);
    RAISE;
END;

详细见:Oracle PL/SQL 异常处理详解

8.3 性能

-- BULK COLLECT
SELECT * BULK COLLECT INTO v_emp FROM employees LIMIT 1000;

-- FORALL
FORALL i IN 1..v_ids.COUNT
  INSERT INTO t VALUES (v_ids(i));

详细见:Oracle BULK COLLECT 与 FORALL 详解


9. 注释

9.1 表

COMMENT ON TABLE employees IS '员工信息表';
COMMENT ON COLUMN employees.salary IS '员工月薪(元)';
COMMENT ON COLUMN employees.hire_date IS '入职日期';

9.2 代码

-- 单行

/*
  多行
  说明
*/

CREATE OR REPLACE PROCEDURE sp_hire_emp(
  p_name IN VARCHAR2,         -- 员工姓名
  p_salary IN NUMBER,         -- 月薪
  p_dept_id IN NUMBER         -- 部门ID
) IS
  -- 招聘员工
  -- Author: xxx
  -- Date: 2026-07-21
BEGIN
  ...
END;
/

10. 事务

10.1 短事务

- 业务开始
- DML
- COMMIT / ROLLBACK
- 业务结束

10.2 一致顺序

- 避免死锁
- 表顺序一致
- 行顺序一致

详细见:Oracle 事务与并发控制详解


11. 安全

11.1 SQL 注入

-- DBMS_ASSERT
EXECUTE IMMEDIATE 'SELECT * FROM ' || DBMS_ASSERT.QUALIFIED_SQL_NAME(p_table);

-- 绑定变量
EXECUTE IMMEDIATE 'SELECT * FROM t WHERE id = :id' USING v_id;

11.2 最小权限

- 角色
- 视图
- 存储过程
- VPD

12. 性能

12.1 索引

- 高选择性
- 覆盖
- 复合合理

详细见:Oracle 索引优化策略详解

12.2 执行计划

EXPLAIN PLAN FOR ...;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY));

详细见:Oracle 执行计划详解

12.3 统计信息

EXEC DBMS_STATS.GATHER_TABLE_STATS(...);

详细见:Oracle SQL 调优最佳实践


13. 版本控制

13.1 脚本组织

/db
  /ddl
    /tables
    /indexes
    /constraints
  /dml
  /packages
  /procedures
  /functions
  /triggers
  /views
  /migrations
    /V1.0.0
    /V1.1.0

13.2 命名

- V1.0.0__create_employees.sql
- V1.1.0__add_email_column.sql
- R__update_dept_data.sql

13.3 工具

- Flyway
- Liquibase
- Git

14. 测试

14.1 单元测试

-- UTPLSQL
CREATE OR REPLACE PROCEDURE test_hire_emp IS
  v_id NUMBER;
BEGIN
  sp_hire_emp('Alice', 5000, 10, v_id);
  ut.expect(v_id).to_be_gt(0);
END;
/

14.2 集成测试

- 端到端
- 业务流程
- 性能

15. 代码审查

15.1 检查项

- 命名规范
- 性能(索引/绑定)
- 安全(注入)
- 异常处理
- 注释
- 测试

15.2 工具

- Code Review
- 静态分析
- SQL Inspector

16. 文档

16.1 数据字典

- 表说明
- 列说明
- 关系
- 约束

16.2 API

- 过程说明
- 参数
- 返回
- 异常
- 示例

17. 常见反模式

17.1 避免

- SELECT *
- 隐式转换
- 函数阻止索引
- OR 性能
- 不必要 DISTINCT
- UNION 改 UNION ALL
- 拼接 SQL
- 全表扫描
- 过度复杂 SQL

17.2 推荐

- 明确列
- 绑定变量
- 索引友好
- 现代语法
- 简单清晰

18. 最佳实践

  1. 命名规范:一致
  2. 关键字大写:清晰
  3. 明确列:性能
  4. 绑定变量:减少解析
  5. 现代 JOIN:清晰
  6. 异常处理:完整
  7. 注释:说明
  8. 版本控制:管理
  9. 测试:验证
  10. 审查:质量

19. 参考资料

[1] Oracle Database SQL Tuning Guide 19c https://docs.oracle.com/en/database/oracle/oracle-database/19/tgsql/