
简介Oracle 数据库设计开发规范是一份面向数据库设计人员、后端开发工程师与 DBA 的实用文档用于解决建库建表、命名混乱、权限失控、备份缺失等常见工程问题适合从入门到进阶的 Oracle 开发者对照落地。资源包共 1 个文件为 doc 格式的规范文档压缩包约 245KB内容按章节组织便于逐条查阅与团队内部培训使用。文档共 51 页涵盖范围与简介、数据库整体设计规范、数据库对象设计规范、数据库安全规范、数据备份与恢复规范等模块并细化了表、字段、命名、权限分配、数据加密、审计日志、编码规则、测试验证与日常维护等具体条款。目前已有 624 人学习下载读者可据此建立统一的数据库设计标准减少返工与安全隐患提升系统稳定性、可扩展性与开发协作效率。1. 从一次 SQL 审核翻车说起这份 Oracle 设计规范到底管什么上周帮一个朋友看他们新上的业务系统开发环境跑得好好的上线第二天就收到告警一张核心表的全表扫描把 IO 打满了。翻了下建表语句VARCHAR2(4000)的字段建了一堆主键用的是业务流水号字符串连个像样的索引都没有。这种问题在 Oracle 里太常见了——语法能跑通不代表设计过关。这份《Oracle 数据库设计开发规范》就是冲着这类问题来的它不是语法手册而是一套把命名、数据类型、索引、SQL 写法、权限管理全部框死的约束文档适合做后台开发的、做 DBA 的、以及需要评审建表语句的技术负责人。你拿到手之后能直接把它当成团队内部的 check list 用建表前过一遍能省掉后面大量的返工和性能排查。2. 命名与数据类型规范里最容易吵起来的两块2.1 命名规范为什么值得单独拎出来很多人觉得命名是小事但 Oracle 的标识符有硬性长度限制——12.2 之前是 30 字节之后虽然放宽到 128 字节可实际项目里没人真去用满。规范里一般会约定表名用业务模块前缀加下划线比如ORD_ORDER_MAIN字段名不用保留字不用中文拼音缩写索引名带上表名和字段名比如IDX_ORD_ORDER_MAIN_USER_ID。这些约定看着琐碎但真到了几百张表的库里面没有命名规则就是灾难。我见过一个库索引名全是IDX_1、IDX_2后来要删一个废弃索引查了半天才确认删的是哪个。命名规范落地的时候建议直接写进建表模板里。下面这个模板是我自己常用的把表名、字段名、索引名、注释全部占位好开发只需要填空-- 建表模板替换 {模块}_{业务} 和字段定义 CREATE TABLE {MOD}_{BIZ}_MAIN ( ID NUMBER(19) NOT NULL, -- 主键统一用 NUMBER(19) BIZ_CODE VARCHAR2(32) NOT NULL, -- 业务编码定长用 CHAR变长用 VARCHAR2 BIZ_NAME VARCHAR2(128) NOT NULL, -- 业务名称 STATUS CHAR(1) DEFAULT 0 NOT NULL, -- 状态位统一 CHAR(1) CREATE_TIME DATE DEFAULT SYSDATE NOT NULL, UPDATE_TIME DATE DEFAULT SYSDATE NOT NULL, CONSTRAINT PK_{MOD}_{BIZ}_MAIN PRIMARY KEY (ID) ); -- 注释必须补否则后面谁都不知道字段干嘛的 COMMENT ON TABLE {MOD}_{BIZ}_MAIN IS 业务主表; COMMENT ON COLUMN {MOD}_{BIZ}_MAIN.BIZ_CODE IS 业务编码唯一;这段模板里几个点值得说清楚。ID用NUMBER(19)而不是VARCHAR2是因为数值型主键在 Oracle 里做索引和关联的效率更稳而且 19 位刚好覆盖NUMBER的精度范围不会出现隐式转换。STATUS用CHAR(1)而不是VARCHAR2(1)是因为定长字段在行迁移和存储上更可控。CREATE_TIME和UPDATE_TIME用DATE而不是TIMESTAMP除非业务真需要毫秒级精度否则DATE足够且更省空间。注释这块别偷懒Oracle 的COMMENT ON是元数据后面用USER_COL_COMMENTS一查就能生成数据字典。2.2 数据类型选型的几个硬边界规范里对数据类型的约束通常是最细的因为这块直接决定存储和性能。VARCHAR2的长度不要超过 4000超过就用CLOB但CLOB不能建普通索引查询时要注意。NUMBER不带精度的时候Oracle 会按最大精度存容易浪费空间所以金额字段一般写成NUMBER(18,2)。日期字段统一用DATE别混用TIMESTAMP和DATE否则关联查询时会出现隐式转换索引直接失效。还有一个容易忽略的点NULL值在 Oracle 的索引里是不存的。如果某个字段经常用IS NULL查普通 B 树索引帮不上忙得考虑位图索引或者函数索引。规范里一般会写一条业务上非空的字段必须加NOT NULL约束别指望应用层保证。下面这个查询可以帮你快速找出库里哪些字段没加非空约束-- 查当前用户下所有允许为空的字段 SELECT table_name, column_name, data_type, nullable FROM user_tab_columns WHERE nullable Y AND table_name NOT LIKE BIN$% -- 排除回收站对象 ORDER BY table_name, column_name;跑完这个查询如果发现核心业务表的BIZ_CODE、STATUS这些字段是Y那就得回头补NOT NULL。补的时候注意如果表里已经有NULL数据直接加约束会报错得先UPDATE再ALTER TABLE ... MODIFY ... NOT NULL。3. 索引与 SQL 写法规范落地时最见功力的地方3.1 索引不是越多越好但该建的必须建索引规范的核心就两条主键索引自动建外键字段手动建高频查询条件按需建。但实际项目里经常走极端——要么一个索引不加要么每个字段都加。我见过一张 20 个字段的表建了 15 个索引插入性能直接掉一半。规范里一般会约定单表索引数量不超过 5 个组合索引的字段顺序按区分度从高到低排函数索引要单独评审。组合索引的顺序特别关键。比如WHERE STATUS 1 AND CREATE_TIME SYSDATE - 7如果建的是(CREATE_TIME, STATUS)那STATUS就用不上索引建(STATUS, CREATE_TIME)才能两个条件都走索引。这个规则在规范里最好配一个示例不然开发记不住。下面这个脚本可以帮你检查现有索引的使用情况-- 查索引被监控到的使用次数需要先开索引监控 ALTER INDEX IDX_ORD_ORDER_MAIN_STATUS MONITORING USAGE; -- 过一段时间后查 SELECT index_name, table_name, used, start_monitoring, end_monitoring FROM v$object_usage WHERE used NO;如果某个索引USED一直是NO而且确认业务上确实不用就可以考虑删掉。但删之前一定要确认没有隐藏的查询在用最好先在测试库跑一周。3.2 SQL 写法的几条红线规范里对 SQL 的约束通常包括禁止SELECT *禁止在WHERE里对索引字段做函数运算禁止用OR连接不同字段禁止隐式类型转换。这几条每一条都是血泪教训。SELECT *的问题不只是多取字段更麻烦的是当表结构变更时应用层拿到的结果集列数变了容易出问题。对索引字段做函数运算比如WHERE TO_CHAR(CREATE_TIME, YYYY-MM-DD) 2024-01-01索引直接失效得改成WHERE CREATE_TIME TO_DATE(2024-01-01, YYYY-MM-DD) AND CREATE_TIME TO_DATE(2024-01-02, YYYY-MM-DD)。隐式类型转换更隐蔽。比如字段是VARCHAR2你写WHERE BIZ_CODE 123Oracle 会把字段转成数字再比较索引失效。这种问题在开发环境数据量小的时候看不出来上线就翻车。规范里最好直接写死所有字面量必须和字段类型一致字符串加单引号数字不加。-- 错误写法索引失效 SELECT * FROM ORD_ORDER_MAIN WHERE BIZ_CODE 123; -- 正确写法类型匹配走索引 SELECT ID, BIZ_CODE, BIZ_NAME FROM ORD_ORDER_MAIN WHERE BIZ_CODE 123;3.3 执行计划怎么看才不白看规范落地之后怎么验证 SQL 有没有按预期走索引看执行计划。但很多人只看TABLE ACCESS FULL就慌了其实得结合Rows、Cost、Bytes一起看。如果表很小全表扫描比索引扫描还快那走全表扫描是合理的。关键看的是Cardinality估算和实际行数的偏差偏差大说明统计信息过期得重新收集。-- 查看执行计划 EXPLAIN PLAN FOR SELECT ID, BIZ_CODE FROM ORD_ORDER_MAIN WHERE STATUS 1 AND CREATE_TIME SYSDATE - 7; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);看完执行计划如果发现INDEX RANGE SCAN变成了INDEX FULL SCAN或者Cost突然飙高先别急着改 SQL跑一下DBMS_STATS.GATHER_TABLE_STATS收集统计信息很多时候是统计信息不准导致的。4. 避坑与排查规范执行中最容易翻车的五个点4.1 现象建表时用了VARCHAR2(4000)插入报错 ORA-01461原因VARCHAR2(4000)在NLS_LENGTH_SEMANTICS为BYTE时实际能存的字节数受字符集影响中文环境下 4000 字节可能只够存 1000 多个汉字。解决建表时明确用VARCHAR2(4000 CHAR)或者把长度降到 2000 以内超过就用CLOB。4.2 现象主键用SYS_GUID()生成查询越来越慢原因SYS_GUID()生成的是 32 位十六进制字符串作为主键时索引块分裂频繁而且字符串比较比数字慢。解决主键统一用序列SEQ_XXX.NEXTVAL生成数值型 ID或者用IDENTITY列12c 及以上。4.3 现象DELETE大量数据后表空间没释放原因DELETE只是标记删除高水位线没降全表扫描还是扫那么多块。解决确认业务允许后用TRUNCATE TABLE或者ALTER TABLE ... MOVE重建表再ALTER INDEX ... REBUILD重建索引。4.4 现象COUNT(*)在亿级表上跑几分钟不出结果原因Oracle 的COUNT(*)要扫全表或者最小的索引数据量大就是慢。解决如果只是要判断有没有数据用SELECT COUNT(*) FROM (SELECT 1 FROM TABLE_NAME WHERE ROWNUM 1)如果真要精确计数考虑建物化视图或者用/* PARALLEL */提示。4.5 现象应用连接池报 ORA-00060 死锁原因两个会话互相等待对方持有的锁通常是UPDATE顺序不一致导致的。解决规范里约定所有UPDATE按主键排序执行或者用SELECT ... FOR UPDATE NOWAIT快速失败避免长时间等待。5. 把规范变成自动化检查几个能省人力的脚本规范写在文档里靠人肉 review 迟早会漏。我一般会把几条硬性规则写成 SQL 脚本定期跑一遍输出不合规的对象清单。比如检查没有注释的表、没有主键的表、索引过多的表、字段类型不合理的表。下面这个脚本查的是没有主键的表-- 查没有主键的表 SELECT t.table_name FROM user_tables t WHERE NOT EXISTS ( SELECT 1 FROM user_constraints c WHERE c.table_name t.table_name AND c.constraint_type P ) AND t.table_name NOT LIKE BIN$%;跑出来如果有核心业务表那就得补主键。补的时候注意如果表里已经有重复数据得先清理。另一个常用脚本是查索引数量超过 5 个的表-- 查索引数量超过 5 个的表 SELECT table_name, COUNT(*) AS idx_count FROM user_indexes WHERE table_name NOT LIKE BIN$% GROUP BY table_name HAVING COUNT(*) 5 ORDER BY idx_count DESC;这两个脚本我一般放在一个check.sql里每周跑一次输出结果直接发给开发负责人。时间长了大家建表前会自己先跑一遍省得被点名。还有一个进阶用法把规范里的命名规则写成正则用REGEXP_LIKE去匹配表名和字段名。比如规定表名必须是大写字母加下划线且以模块前缀开头-- 查不符合命名规范的表名 SELECT table_name FROM user_tables WHERE NOT REGEXP_LIKE(table_name, ^[A-Z]_[A-Z_]$) AND table_name NOT LIKE BIN$%;这个脚本能揪出那些用拼音缩写、用数字开头、或者带特殊字符的表名。跑完把结果整理成清单在团队周会上过一遍比口头强调管用得多。从那以后我每次接手新库第一件事就是跑一遍这几个检查脚本把不合规的对象列出来再决定是先改还是先忍着。规范这东西写出来只是第一步能自动查、能落地才算真用起来。希望帮到你。本文还有配套的精品资源点击获取