序号 | 术语/缩略语 | 全称和说明 |
---|---|---|
1 | 表(TABLE) | 数据库中用于存储数据的基本存储单位 |
2 | 派生受权 | 给用户受权时,使用with grant option,使得被受权的用户能够将被受权的对象受权给其它用户 |
3 | 接口表 | 当经过goldengate或者ETL方式进行数据同步的时候, 在目标端建立的与源表结构一致的同构表。 |
4 | 基表 | 存放基础数据, 配置数据的表, 这些数据仅提供给业务处理过程使用, 而不会在业务处理过程当中被修改。 基表中的数据很是稳定, 极少修改,也几乎不会外键关联到其它表。 |
2.1.1 表的设计必需要知足第一范式。 sql
在表设计中,不容许字段出现二义性。例如,表中不能有这样的字段,字段的值是由几位数字组成的代码,第一位表示客户类型,第二位表示渠道类型……,这种设计不符合第一范式,不容许出现。 数据库
2.1.2 建议1:表的设计应尽可能知足第三范式。 缓存
数据库三范式的说明请参见 附录3.2 数据库三范式说明。 jsp
2.2.1 create table语句参数不能包含storage选项,不能包含nologging选项, nologging 会影响数据库的灾备和恢复。 数据库设计
例如:如下建表语句,tablespace后面的部分不能包含。 函数
create table AREA_DEFINE ( created_by varchar2(100), created_date date, updated_by varchar2(100), updated_date date, area_code varchar2(4) ) tablespace PCISBASE_DATA pctfree 10 initrans 1 maxtrans 255 storage ( initial 5M next 5M minextents 1 maxextents unlimited pctincrease 0 ) Nologging;
create table AREA_DEFINE ( created_by varchar2(100), created_date date, updated_by varchar2(100), updated_date date, area_code varchar2(4) ) ;
而在生产数据库版本为Oracle 9i时, 则在建表时须要加上MONITORING参数。
MONITORING参数说明:建立表时设置MONITORING参数, 使得Oracle跟踪对表的DML操做,预估DML操做所影响的记录数量。在Oracle 9i中, MONITORING参数不是默认的,须要手工执行,而在Oracle 10g及以上版本中, 该参数为默认设置。 工具
2.3.1 表中一条记录全部字段的长度不能超过该数据库的db_block_size大小 性能
当字段总长度大于数据的db_block_size时,会产生大量的行连接,影响到表访问的效率,应当避免。所以在对表设计时,要求字段总长度不能超过数据的db_block_size大小。 测试
字段的总长度计算方法为全部字段长度相加的总和。 如以C_INFO_TEMPLATE表为例,该表有8个字段, 它所在的库的db_block_size为8192. ui
COLUMN_NAME | DATA_TYPE | DATA_LENGTH |
---|---|---|
INFO_TEMPLATE_CODE | NUMBER | 22 |
CREATED_BY | VARCHAR2 | 100 |
CREATED_TIME | DATE | 7 |
UPDATED_BY | VARCHAR2 | 50 |
UPDATED_TIME | DATE | 7 |
INFO_TEMPLATE_NAME | VARCHAR2 | 100 |
SPECIAL_CASE_CODE | VARCHAR2 | 6 |
IS_TEMP | VARCHAR2 | 2 |
则该表的字段长度为 22+100+7+100+7+50+6+2 = 294字节,知足规范。
能够在生产环境中使用以下sql查询表的长度:
select sum(data_length) as "total column length" from user_tab_columns where table_name='&table_name';
能够在生产环境中使用以下sql获取数据块大小:
SQL> show parameter db_block_size
2.3.2 字段必须定义正确的数据类型
在设计表结构时,对于只存储数字的字段应定义成数字类型,只存储字符的字段定义成字符类型,只存储日期的字段定义成日期类型,以减小使用过程当中的数据类型转换。
好比有Customer表, 字段定义以下:
Column name | Type | Is Null? |
---|---|---|
Cust_no | Varchar2(50) | N |
Cust_name | Varchar2(255) | Y |
Date_birth | Varchar2(50) | Y |
sex | Varchar2(50) | Y |
其中错误的定义有:
Cust_no字段中只存储数字。因此须要定义为number, 不能定义为varchar2。
date_birth字段应该定义为date, 不能定义为varchar2。
sex字段的定义过长,只须要定义varchar2(1)就能够了,咱们记录性别为F(女)或M(男)。
2.3.3 在表中不容许使用Long类型字段; 可使用Lob数据类型字段, 但在Oracle 11g中, 必须使用secure file。
LOBs数据对象分为两类:
使用LOB类型, 有以下参数须要设置:
所以,在使用LOB字段时必须设置DISABLE STORAGE IN ROW。
仅在知足如下条件:
只有在最终结果集中会返回该数据行的LOB数据时, 才会对该数据行所在的block进行读取。 且知足如下两个条件之一
a) 该表从不会与其它表关联使用.
b) 若是有与其它表关联,则老是经过主键或者索引进行关联.
才使用ENABLE STORAGE IN ROW。
chuck设置 | 存储LOB所占用磁盘大小 | 磁盘利用率(%) | I/O读取次数 |
---|---|---|---|
8K | 8K | 62.5 | 1 |
16K | 16K | 31.25 | 1 |
32K | 32K | 15.63 | 1 |
LOB size为25K :
chuck设置 | 存储LOB所占用磁盘大小 | 磁盘利用率(%) | I/O读取次数 |
---|---|---|---|
8K | 32K | 78.13 | 4 |
16K | 32K | 78.13 | 2 |
32K | 32K | 78.13 | 1 |
Db_Block_size: 8K | Db_Block_size: 16K | Db_Block_size: 32K | |
---|---|---|---|
LOB数据主要分布区间在【0,8k】 | 8K | 16K | 32K |
LOB数据主要分布区间在【8k,16k】 | 16K | 16K | 32K |
LOB数据主要分布区间在【16k,32k】 | 32K | 32K | 32K |
LOB数据主要分布区间大于32k | 32K | 32K | 32K |
若是有须要对存储和性能进行综合考虑,可在该表使用一段时间后, 对LOB字段数据状况进行分析
可以使用下面的sql对LOB字段进行全表分析
《数据库开发管理规范_全表分析LOB.rar》
若是LOB表数据量较大,也可以使用下面的sql对LOB字段进行采样的分析
《采样分析LOB说明.rar》
在Oracle 11g的Securefile 方式中, CHUNK 的最大值为64MB,且会自动适应LOB数据的大小, 所以无需设置CHUNK参数。
举例: 建立带有LOB字段的表
create table customer ( id_customer raw(32), customer_name varchar2(100), customer_photo clob ) lob (customer_photo) store as ( tablespace hrmslobdata disable storage in row chunk 32k pctversion 10 nocache logging );
所以: 数据库使用AL32UTF8字符集时:
LOB数据字节数= (汉字字符数*3 + 英文字符数*1 )/ ( 1 - PCT_FREE )
数据库使用GBK时: LOB数据字节数= (汉字字符数*2 + 英文字符数*1 )/ ( 1 - PCT_FREE )
若是使用BLOB字段类型,BLOB数据长度与原二进制文件大小一致。
create table customer ( id_customer raw(32), customer_name varchar2(100), customer_photo blob ) lob (customer_photo) store as securefile ( tablespace hrmslobdata disable storage in row nocache logging );
Securefile用法和测试按列请见:附录3.3。
2.3.4 表和字段必须有comment中文注释
表和字段必须有中文注释,注释采用comment on的形式,如:
Comment on table AREA_DEFINE is ‘地区定义表’;
Comment on column AREA_DEFINE.AREA_CODE is ‘地区代码’;
2.3.5 为了保证表中数据的完整性,在设计表时,必须考虑给各字段加上适当的约束
约束的类型有非空约束,惟一性约束,主键约束,外键约束,check约束等;
Check 约束仅适用于Boolean类型字段的检查需求, 或者是一些二元属性的字段,好比表示性别字段,只有’F’,’M’ 两种值,也可以使用Check约束。而对于其它的列值检查必须采用基表+主外键的方式。
2.3.6 除日志表、临时表外,其它新建表中,必须有数据建立人,建立时间,修改人,修改时间这4个字段,四个必须字段异动的内容必须经过trigger方式实现,不能经过程序代码实现,字段名及数据类型、长度须与下面的保持一致。
建立人 | created_by | varchar2(100) | not null; |
建立时间 | created_date | date | not null; |
修改人 | updated_by | varchar2(100) | not null; |
修改时间 | updated_date | date | not null; |
注意:这四个审计字段仅适用于记录该表自身数据的变化,若是以该表为目标表的源表须要同步审计字段信息,则要求该目标表新建四个审计字段存放源表数据,新字段命名需和目标表审计字段区分开来,参考示例:
源建立人 | src_created_by | varchar2(100) | not null; |
源建立时间 | src_created_date | date | not null; |
源修改人 | src_updated_by | varchar2(100) | not null; |
源修改时间 | src_updated_date | date | not null; |
2.3.7 对于经过UM登录系统或者直接用脚原本操做数据的状况,created_by,updated_by必须插入员工UM编码 。
2.3.8 全部外键上都必须建立索引。
若没有对外键创建索引,则在对父表DELETE操做或者UPDATE关联父表的键值操做时,会对子表产生全表独占锁,引起性能问题。
2.3.9 全部表必需要主键,除了temparory tablespace 中的临时表之外.
2.3.10 建立主键时必须先建立索引,再建立主键。
先建立惟一索引,再基于该索引建立主键。
在删除主键时若遗忘指定keep index,则删除主键的同时会将主键索引也一并删除。若仍然有SQL需使用该索引时就会引起性能问题,并且要重建该索引也可能须要花费较长时间。
所以需采用先建立索引再建立主键的方式,避免上述状况的发生。
以CUSTOMER表为例,如今要在ID字段建立主键
col_name | type | is_null |
---|---|---|
id_cust | varchar2(32) | N |
cust_name | varchar2(255) | Y |
date_birth | Date | Y |
sex | varchar2(1) | Y |
create unique index pk_customer_id on customer (id_cust); alter table customer add constraint pk_customer_id primary key (id_cust) using index pk_customer_id;
错误的脚本:
alter table customer add constraint pk_customer_id primary key (id_cust) ;
2.3.11 除接口表和基表的主键字段之外, 全部主键字段必须使用DB级 sys_guid值做为pk值, 字段类型统一为VARCHAR2(32)。对应子表的外键字段也应该使用VARCHAR2(32),保持类型相同。
例:
Insert into customer (id_cust, cust_name, date_birth, sex) values ( sys_guid() ,’Jimmy’,null,’M’);
2.3.12 选择主键必须遵行的原则
col_name | type | is_null |
---|---|---|
phone_number | number(20) | N |
cust_id | number | N |
status | varchar2(1) | N |
date_register | date | N |
col_name | type | is_null |
---|---|---|
Id_ims_phone_number | varchar2(32) | N |
phone_number | number(20) | N |
cust_id | number | N |
status | varchar2(1) | N |
date_register | date | N |
col_name | type | is_null | description |
---|---|---|---|
id_cust | varchar2(32) | N | 客户ID |
id_couse | varchar2(32) | N | 课程ID |
course_score | number | Y | 选修得分 |
id_cust字段与id_course字段这两个字段是复合惟一的,但不能在这两个字段上建立复合主键,而是须要增长一个字段id_cust_grade字段做为主键, 使用SYS_GUID值作为主键,字段类型为varchar2(32)。而在id_cust和id_course两个字段上建立惟一索引。以下:
col_name | type | is_null | description |
---|---|---|---|
id_cust_grade | varchar2(32) | N | ID |
id_cust | varchar2(32) | N | 客户ID |
id_course | varchar2(32) | N | 课程ID |
course_score | number | Y | 选修得分 |
2.3.13 不容许修改表上已有的主键结构
表上的主键一旦肯定,将不容许被修改,由于修改主键将会带来一系列的问题。
除非由于业务规则发生改变而致使不得不修改主键的状况发生, 此时修改主键必须知足如下条件:
a) 新主键定义必需要知足规范2.3.12
b) 原主键定义不知足规范2.3.12.3
c) 原主键不是其它任何一张表的外键
当主键是其它子表的外键时,修改主键会致使以它做为外键的子表上产生锁,若是子表在这个外键上有索引,则会产生行锁,若是没有索引,则会产生表锁。
删除原有主键约束时,必须评估主键对应的索引是否须要保留, 若是不要保留,须要使用Quest SQL Optimizer工具的impact analyzer 进行对比测试,评估变动影响。
若删除了主键而没有保留索引,则根据原主键查询的SQL语句将再也不走原主键的惟一索引,执行计划发生改变,极有可能致使SQL出现性能问题,此时须要评估这种改变带来的性能问题。
2.3.14 建议3: 全部业务上有主外键关系都必须在数据库中建立主外键。
2.3.15 惟一键的建立方式,与主键相同,即先建索引,而后加惟一键
2.3.16 在修改表时,若是增长有default值的列或者修改字段的非空属性,必须先作ddl增长字段,再作dml更新值,而后再作ddl增长字段的default属性或非空属性。但若是所修改数据库是Oracle 11g版本,则无须此操做。
alter table test1 add is_lbs varchar2(6) default 'YES';
须要改成ddl,dml和ddl三个脚本:
alter table test1 add is_lbs varchar2(6); update test1 set is_lbs='YES' where ……; (该dml语句须要支持断点续作和分段提交) alter table test1 modify is_lbs default ‘YES’;
修改表的某字段为 not null,应该先将该列值为空的记录update为非空,再增长not null约束。例如:对于某个table,修改字段A为 not null :
update test set A=’’ where A is null ……; (该dml语句须要支持断点续作和分段提交) alter table test modify A not null;
对表增长有default值且not null的列,应该先作ddl增长字段,再作dml更新值。
例如:对于某个table,增长一个有default值且not null的列,须要将以下ddl:
alter table test1 add is_lbs varchar2(6) default ‘YES' not null;
改成ddl,dml和ddl三个脚本:
alter table test1 add is_lbs varchar2(6); update test1 set is_lbs='YES' where …...; (该dml语句须要支持断点续作和分段提交 ) alter table test1 modify is_lbs default ‘YES’ not null;
对于表数据的备份,请参见《DML数据备份修改管理规范》。
alter table test1 modify is_lbs default ‘YES’ not null;
Oracle 11g 会把默认值存储在数据字典中,而不须要先对表作update操做
2.3.17 应用程序中若须要truncate表中的数据,必须采用DBA统一编写的truncate_table过程来实现。不容许为任何业务用户授予drop any table的权限。
2.3.18 对于大表的定义: 将容量超过2G的表定义为大表。
在数据库设计时须要对大表考虑是否进行分区,数据清理,以及归档操做。
Student Advisor Adv-Room Class1 Class2 Class3
----------------------------------------------------------------------------------------------
1022 Jones 412 101-07 143-01 159-02
4123 Smith 216 201-01 211-02 214-01
一个student 会对应多个class, 但上表中使用class1,class2,class3 的设计方式会带来麻烦。知足第一范式的设计应该为:
Student Advisor Adv-Room Class
------------------------------------------------------------------
1022 Jones 412 101-07
1022 Jones 412 143-01
1022 Jones 412 159-02
4123 Smith 216 201-01
4123 Smith 216 211-02
4123 Smith 216 214-01
表中的数据只应该依赖于表的主键。例如在财务系统中客户的地址, 会在客户,订单,发货,发票,收账的环节都须要。所以应该将客户的地址放在单独的一个表中,好比客户表或者地址表。而不是将它在以上每个表都保存一份。继续上面的例子,虽然已经知足第一范式,但注意到Class字段并非函数依赖主键student,不知足第二范式。须要将class拿出来和student 单独组成一个表,以知足第二范式:
Student:
Student Advisor Adv-Room
-----------------------------------------------------
1022 Jones 412
4123 Smith 216
Registration:
Student Class
-------------------------------------
1022 101-07
1022 143-01
1022 159-02
4123 201-01
4123 211-02
4123 214-01
Student:
Student Advisor
----------------------------------
1022 Jones
4123 Smith
Faculty: Name Room Dept ----------------------------------------- Jones 412 42 Smith 216 42