Oracle 数据库设计约束:
一、建表约束
【强制】对于流水表,若记录数超过1000W行以上,应使用分区表(parition)
解读:大表使用分区表可以有效提高查询性能,便于数据清理。若其他大表有性能需要,也可以使用分区技术。
【强制】 表记录长度不能超过1个 block/page
解读:表记录超长对数据库性能会有影响,若单条记录仅仅超出一点,还会产生较大的空间浪费。
【强制】 大型数据库,应该为应用建立专门的表空间,数据与索引表空间分开,流水表与历史表应设立专用表空间
解读:针对大型数据库,交易表、流水表、历史表应开辟专用的表空间。在数据迁移、备份恢复过程中以表空间为单位,具备以下优点:
1)便于数据迁移;
2)便于构造小的测试环境;
3)便于构造小的容灾环境。
大表建议拆分为交易表、历史表,结合多表空间存放,可有效降低触发全表扫描时的性能问题,提高交易性能;降低数据清理对交易的影响。
【强制】 应用用户没有授予管理员权限
解读:严格的权限管理能有效避免不必要的操作失误。
【强制】 生产环境建表或表插入时,禁止使用 nologging 选项
解读:该操作会导致数据库恢复时出现坏块,导致表无法使用。
【强制】 对分区表进行维护后,需要重建全局索引
解读:对分区进行维护后全局索引会失效。
【强制】建表时需要用 comment 语句对表和字段增加注释
解读:规范的建表和注释便于后续维护和管理。
【强制】sequence 应该设置 cache 为1000以上,并设置为 noorder
解读:针对高并发系统,若对 Sequence 没有严格的序号要求,应设置 cache 为1000以上,缺省的序列 Cache 值为20,无法满足高并发要求。
【建议】高并发 OLTP 交易系统尽量避免使用大字段(BLOB、CLOB、LONG)
解读:因 LOB 字段结构特点,高并发系统中 LOB 字段时长出现导致系统运行缓慢的问题。被删除或更新的BLOB字段所占用空间不会自动批量回收,若表存在大量删除、更新操作时,BLOB 所在 Segments 会迅速耗尽空间,新的INSERT需要空间时,会在高水位线上加锁后,回收曾使用但已经过期的BLOB空间,因该操作效率很低,数据库会有大量的 ‘enq:HW - contention’ 等待,相关 SQL 会由于该等待而串行执行,业务受影响十分严重。
二、SQL约束
【强制】where 条件里的过滤字段上禁止使用函数
解读:在 sql 的 where 子句中带有索引的列使用函数时,优化器会忽略掉索引导致索引失效。建议将函数应用在条件上,索引是可以生效的。
select * from staff where trunc(birthdate) = '01-MAY-82'; //不会用到索引
select * from staff where birthdate < (to_date('01-MAY-82') + 0.9999); //会使用索引
【强制】禁止使用 LIKE ‘%_’进行模糊匹配查询
解读:对字段使用like模糊匹配时,如果不从字段的第一位开始,将无法使用索引,禁止使用。
select * from student where name like 'aaa%'; //'aaa%' 会用到索引
select * from student where name like '%aaa'; //'%aaa' 或者 '_aaa' 不会使用索引
【强制】绑定变量和字段数据类型需要保持一致
解读:字段定义和 SQL 绑定变量传进来的值的类型需要保持一致,否则会导致隐式转换无法使用索引。
例如:dept_id 是一个varchar2型的字段,但在查询时把该字段作为number类型以where条件传给Oracle,这样会导致索引失效。
select * from temp where dept_id = 33333333333 ; //错误的例子
select * from temp where dept_id ='33333333333'; //正确的例子
【强制】在查询中指定所需的列,不要直接使用 ‘*’ 返回所有的列
解读:
(1)在查询中使用 select * 时,需要多做一步查询内部系统目录以便把表中的所有字段名找出来。
(2)明确字段名,将来在表增加字段的时候,不会导致程序报错。
(3)读取不需要的列会增加 CPU、IO、NET 消耗。
(4)无法有效的利用覆盖索引。
【强制】变量和参数在类型和长度必须与表定义的列类型和长度匹配
解读:减少存储空间和 IO 资源的浪费,避免隐式转换而导致不使用索引的情况。
【强制】SQL 语句中的表关联查询不允许超过5个,需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引
解读:优化器对与多表连接查询的处理效果不佳,应尽可能减少多表连接的情况,关联字段需要有索引避免不必要的全表扫描,提高执行效率。
【强制】禁止使用触发器
解读:考虑到降低数据库的复杂度,提高可维护性,减少不可预知的风险,禁止使用触发器。
【强制】对于很大的表进行全表删除时,不允许使用全表 delete,应用 truncate 或 drop 重建
解读:delete 语句是 dml,该操作会放到 rollback segment 中,事务提交后才生效;delete 语句不影响表所占用的 extent,高水线(high watermark)保持原位置不动;而 truncate 会将高水线复位(回到最开始)。
另外删除速度一般来说:drop > truncate > delete
【强制】数据清理时,应分批提交降低事务长度,一般每个事务不得超过10万行
解读:单个事务过长容易造成数据库 undo 资源不足回滚。
【强制】表在大量增删改操作后,特别是数据加载之后应立即做统计信息收集
解读:表在大量增删改操作后,统计信息不准确会导致 SQL 语句效率变差,影响性能。
【强制】批量中使用的临时表,若一次导入大量数据进行批量处理,需要在导入大量数据之后,进行批量处理之前,手工进行统计信息收集
解读:收集统计信息,确保优化器提供的执行计划是最优的
【强制】对分区表的访问需要带上分区键作为过滤条件
解读:对分区表的访问语句效率取决于 where 条件字段,使用分区键作为过滤条件才能有效利用分区表的机制。
【强制】大批量插入删除更新需分批提交,更新记录数超过原表记录数10%或超过100W条,需在更新后手工收集统计信息
解读:大批量数据插入删除应分批提交,以免造成数据库 undo 资源不足回滚。在操作完成后需手工收集统计信息,确保统计信息的准确性。大批量数据删除后建议对空间实施回收或重组。
【强制】使用 rownum 实现分页,应使用三层嵌套,并在最里层进行排序
解读:
【建议】针对存在大量 insert 和 delete 操作的表,应定期对索引进行重建
解读:表在大量 insert 和 delete 操作后,数据表会产生大量碎片,索引可能会很大,这类表需要考虑定期重建,以提高效率。
【建议】OLTP 系统中 SQL 尽量使用绑定变量,批量系统中,语句过滤条件中的列对于不同取值记录分布不均匀,而是有较大偏差的情况下,应避免使用绑定变量
解读:SQL 在数据库的处理分为分析和执行两个步骤,不含非绑定变量的SQL只需要分析一次,含非绑定变量的 SQL 每次执行前都需要分析;在批量过程中,若语句过滤条件中的列对于不同取值记录分布不均匀,而是有较大偏差的情况下,使用绑定变量会导致不同的代入值选择同一执行计划,在很多情况下会导致糟糕的语句执行效率,应避免使用绑定变量,由 Oracle 根据不同取值重新解析生成执行计划更好。
【建议】避免使用全表扫描
解读:对于小表或代码表的访问,全表扫描也许是合理的,其他情况下应尽量避免全表扫描,提高执行效率。
三、索引约束
【强制】 分区表上如无特别原因不使用全局索引
解读:分区表使用 global index 或 local index 因根据实际的业务需要来设计,应尽量将业务需要统计的信息放在同一个分区中,使用 local index 使分区表的性能最大化。若需要使用 global index,需说明原因,对分区进行维护后全局索引会失效,应特别注意。
【强制】 OLTP系统每张表索引不超过5个
解读:控制索引数量可以减少不必要的索引空间维护和使用,对于经常插入、更新、删除数据的表应减少索引数量,过多的索引会导致索引开销大,影响性能。
【强制】 复合索引字段不超过3个,必须将区分度更高的字段放在左边
解读:复合索引的设计应综合考虑前缀性和可选性,索引字段不宜过多,应尽可能将区分度高,查询使用较频繁的字段放在左边,这样能够一开始就有效的过滤掉无用数据。在写 SQL 时,若WHERE条件中包含多个条件,应看表上是否有线程的联合索引可使用,注意各个条件的顺序应尽量和复合索引字段顺序一致。
【强制】 没有重复索引(如 a 和 a,b 列都建了索引)
解读:避免在表上建立重复的索引如复合索引 (a,b) 和单列索引 a,降低索引的维护成本。
【强制】 外键的子表关联字段上必须有索引
解读:如果使用了外键约束,子表的关联字段上必须创建索引,否则主表的每一条记录删除,都会导致对子表一次全表扫描。
【强制】 创建和重建索引时,需要带 online 选项
解读:默认创建和重建索引时,会对原表上锁,影响表的更改、删除操作,需要带选项 online,即使增加了 online 选项,也应该避开业务高峰时操作。索引创建或重建完成后需要进行统计信息收集。
【强制】 避免在更新频繁、区分度不高的列上单独建立索引
解读:区分度不高的列单独创建索引的优化效果很小,但是较为频繁的更新则会让索引的维护成本更高。
四、存储过程约束
【强制】存储过程使用中必须要有异常捕获机制
解读:合理的异常捕获能够避免造成应用程序状态不明的问题,便于问题分析和定位。
【强制】存储过程中如果打开了 dblink、cursor 等资源,在存储过程退出时必须关闭上述资源
解读:dblink session 在基于连接池的管理中可能会引起目标管理系统的 session 泛滥,消耗进程资源。 cursor 同理,在使用完毕后关闭游标,降低资源争用和浪费。
五、系统层级
【强制】数据库长连接需要有手段检测异常中断,中断后应有重连机制
解读:提高资源利用率,确保应用在一定时间内有自我修复能力
【强制】数据库连接字符串配置:列出所有 IP 地址
解读:确保能够实现失败转移功能
【强制】数据库连接字符串配置:不使用物理 IP
解读:物理 IP 在服务器宕机后可能导致应用无法重连
【强制】数据库连接字符串配置:开启 failover
解读:确保数据库集群中任何一个节点的故障不会影响用户使用,开启 failover 后,连接到故障节点的用户会被自动转移到健康节点。
【强制】数据库连接字符串配置:关闭load balance
解读:实现只使用 RAC 一个实例,防止数据在两个节点之间大量传输,影响性能。