表設計規範

此處請填入文檔中的專業術語及解釋。
序號 術語/縮略語 全稱和說明
1 表(TABLE) 數據庫中用於存儲數據的基本存儲單位
2 派生受權 給用戶受權時,使用with grant option,使得被受權的用戶能夠將被受權的對象受權給其它用戶
3 接口表 當經過goldengate或者ETL方式進行數據同步的時候, 在目標端建立的與源表結構一致的同構表。
4 基表 存放基礎數據, 配置數據的表, 這些數據僅提供給業務處理過程使用, 而不會在業務處理過程當中被修改。 基表中的數據很是穩定, 極少修改,也幾乎不會外鍵關聯到其它表。

二、設計要求規範#

2.一、表設計原則#

2.1.1 表的設計必需要知足第一範式。 sql

在表設計中,不容許字段出現二義性。例如,表中不能有這樣的字段,字段的值是由幾位數字組成的代碼,第一位表示客戶類型,第二位表示渠道類型……,這種設計不符合第一範式,不容許出現。 數據庫

2.1.2 建議1:表的設計應儘可能知足第三範式。 緩存

數據庫三範式的說明請參見 附錄3.2 數據庫三範式說明。 jsp

2.二、表建立參數規定#


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.三、對錶字段的設計規範#

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數據對象分爲兩類:

  • 1)內部LOBs, 內部LOB是指存儲在數據庫中的大對象,包括BLOB,CLOB,NCLOB.
    • BLOB : 使用二進制存儲的大對象,好比存儲圖像,音像和視頻,或者文件.
    • CLOB : 使用數據庫字符集存儲的字符型數據的大對象.
    • NCLOB: 使用數據國家字符集存儲的字符型數據的大對象.
  • 2)外部LOBs, 外部LOB是指存儲在操做系統,而非存儲在數據庫中。數據庫經過BFILE來獲取外部LOB。
    • BFILE : 指向存儲在操做系統的外部LOBs的一種數據類型。

使用LOB類型, 有以下參數須要設置:

  • 1. LOB數據必須存儲在單獨的LOB表空間
由於對LOB字段進行update和Delete操做時候,它的Undo信息不是放在Undo 表空間中, 而是放在本身的LOB段中。 不然若是LOB數據存放在業務表空間時,當對LOB數據更新操做時, 只要業務表空間還有足夠剩餘, 這樣對與業務表空間的剩餘存儲空間預估帶來很大不肯定性。
  • 2. ENABLE/DISABLE STORAGE IN ROW的設置
    • ENABLE STORAGE IN ROW: 表示容許小於4000 bytes 的LOB存放在數據行中,而只將大於4000 bytes的數據存放在LOB段中。
      • 利: LOB數據老是隨表block一同讀取,無需對每一行進行額外訪問LOB段來獲取LOB數據。
      • 弊: 會使得每一個block所包含的rows大爲降低, 當訪問相同量的數據時,須要訪問更多的塊。對執行效率有較大影響。
    • DISABLE STORAGE IN ROW: 表示不管LOB 數據是否大於4000 bytes, 都存儲在LOB段中。
      • 利: 因爲LOB數據不與LOB行一塊兒存儲,使得表中每一個block中可包含較多的rows, 當在不須要讀取LOB字段時(包括SQL執行計劃中子步驟返回的行數),會大大減小所需讀取的block數量。
      • 弊: 每一行LOB數據的讀取都須要額外訪問LOB段的3個block, 當需返回較多LOB數據時,會讀取大量的block塊。

所以,在使用LOB字段時必須設置DISABLE STORAGE IN ROW。
僅在知足如下條件:
只有在最終結果集中會返回該數據行的LOB數據時, 纔會對該數據行所在的block進行讀取。 且知足如下兩個條件之一
a) 該表從不會與其它表關聯使用.
b) 若是有與其它表關聯,則老是經過主鍵或者索引進行關聯.
才使用ENABLE STORAGE IN ROW。

  • 3. 合理設置storage as (CHUNK bytes) 參數
該參數是針對LOB存儲段的設置,最小的LOB CHUNK的大小必須是數據庫塊(DB_BLOCK_SIZE)的整數倍。CHUNK的最大值爲32k, 且須小於表空間的extend中NEXT的值。因爲在一個CHUNK塊中最多隻能存儲一行LOB數據,所以CHUNK的設置會影響到LOB數據的讀取效率和磁盤使用率。
分別以LOB size爲5K 和25K大小爲例:
LOB size爲5K :
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
所以,基於性能方面的考慮, 在新建表時可參考以下對Chunk參數進行配置:
  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(info)
若是LOB表數據量較大,也可以使用下面的sql對LOB字段進行採樣的分析
採樣分析LOB說明.rar(info)
在Oracle 11g的Securefile 方式中, CHUNK 的最大值爲64MB,且會自動適應LOB數據的大小, 所以無需設置CHUNK參數。

  • 4. 必須設置爲storage as (nocache)
storage as (nocahce) 表示LOB段不通過buffer cache緩存,直接讀與直接寫。這樣能夠提升對其它數據塊在buffer cache的命中率,減小由於使用LOB而對整個業務的影響。
  • 5. 必須設置爲storage as (logging)
Logging屬性只對nocache方式生效。
由於nologging方式對LOB段作的DML操做不記錄redo日誌,會影響Data Guard的同步,因此必須採用logging方式。
  • 6. 必須設置PCTVERSION爲默認值10
PCTVERSION用來管理LOB字段鏡像數據的空間百分比,在LOB數據的更新過程當中,ORACLE沒有用UNDO TABLESPACE,而是從LOB字段所在的表空間裏劃分一段空間來作鏡像空間的, 這個空間的大小由PCTVERSION參數控制,默認值爲10,表明劃分表空間的10%做爲鏡像空間, 每一個鏡像空間的單元大小由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      );

  • 7. 如何預估存儲在數據庫中LOB數據的字節數
使用LOB類型時,對存儲在LOB字段數據的字節數進行預估很重要,對Storage 參數設置,以及佔用磁盤空間估算都有影響。
主要有兩方面的影響:
    • a) 字符集設置的影響, 當數據庫使用AL32UTF8 時,會使用3 個byte 存儲漢字, 1個byte 存儲英文字符。而若是數據庫使用GBK字符集, 則使用2個byte存儲漢字,1個字節存儲英文字符。
    • b) 若是LOB數據會大於一個Block size , 還須要考慮PCT_FREE 設置的影響。PCT_FREE 表示在每一個Block中保留的字節數, 默認爲10%。

所以: 數據庫使用AL32UTF8字符集時:
LOB數據字節數= (漢字字符數*3 + 英文字符數*1 )/ ( 1 - PCT_FREE )
數據庫使用GBK時: LOB數據字節數= (漢字字符數*2 + 英文字符數*1 )/ ( 1 - PCT_FREE )
若是使用BLOB字段類型,BLOB數據長度與原二進制文件大小一致。

  • 8. 在Oracle 11g 中,必須使用secure file 方式
SecureFiles功能是Oracle11g數據庫對LOB數據類型的從新設計,可大幅度的提升性能、可管理性和簡化應用的開發。SecureFiles 集外部文件和數據庫 LOB 方法的優勢於一身,能夠存儲非結構化數據,容許加密、壓縮、重複消除等等。
使用SecureFiles 方式無需設置CHUNK, PCTVERSION 參數. 在Oracle 11g中CHUNK的大小可變,且最大值爲64MB。
能夠參考例子以下:
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 選擇主鍵必須遵行的原則

  • 一、 主鍵字段必須不能爲空值
這個是主鍵約束的一個基本前提,主鍵所在的字段上,不容許有空值出現。
  • 二、 永遠不會改變.
主鍵設計的初衷就是爲了惟一標示一條記錄,所以它自己是不該該發生變化的。一個好的主鍵設計是,全部主鍵字段的值決不會隨着之後業務需求的變化而發生改變,而是一成不變的,一旦生成就再也不改變。
  • 三、 自己不是識別值
主鍵字段的值並不該該有其它任何含義,僅僅是其做爲主鍵的標示意義。由於具備含義的值一般會隨着業務需求的變化而發生改變。也就是說, 在業務系統中, 主鍵除了做爲表關聯之外,不會出如今任何過濾條件中。
例如, 有一張表ims_phone_number記錄了客戶接收短信的手機號碼。在這張表中,手機號碼字段phone_number是惟一的,不能重複。 以下:
col_name type is_null
phone_number number(20) N
cust_id number N
status varchar2(1) N
date_register date N
但在選擇主鍵時,不能使用phone_number字段做爲主鍵, 由於在這個業務中, 手機號碼具備實際意義,它在現實世界中就是一個接收終端的標識,而不只僅是在數據庫中。所以須要另外增長一個字段 Id_ims_phone_number 來做爲主鍵, 該字段類型爲varchar2(32),使用SYS_GUID值作爲主鍵.
以下:
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
  • 四、 選擇單一字段來作主鍵
選擇單一的字段列來做爲主鍵,這樣與其它表關聯時,關聯關係最簡單。對於在邏輯上有多個字段才能肯定惟一的狀況, 不容許在多個字段建立複合類型的主鍵,而是須要添加一個字段做爲主鍵, 字段類型爲varchar2(32), 使用SYS_GUID值作爲主鍵。
如如下表爲例:
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版本,則無須此操做。

  • 1. 對於Oracle 11g之前版本:
例如:對於某個table,增長一個有default值的列,不容許直接使用以下ddl來實現:
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數據備份修改管理規範》。

  • 2. 對於Oracle 11g,能夠直接使用添加一個指定默認值的新列。如上面的修改在Oracle 11g中可直接執行下面腳本。
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的表定義爲大表。

在數據庫設計時須要對大表考慮是否進行分區,數據清理,以及歸檔操做。

3 附錄#

3.1. 表建立案例#

案例.txt (info)

3.2. 數據庫三範式說明#

規範化是組織數據的一個過程,當建立表以及表之間的關係時,經過消除冗餘和不一致的依賴來保護數據,以及使數據庫更靈活。
冗餘數據浪費磁盤空間,並由此帶來維護的問題。若是同一數據被存儲在多個地方,那麼必須按照相同的方式修改全部地方的數據。 但若是該數據只存儲在一個地方,好比客戶的地址只存放在客戶表中,那麼修改起來就很是的容易。
不一致的依賴是指這樣的狀況:咱們從客戶表中查看客戶的地址,是符合一般認識的;但若是要去客戶表中查看負責該客戶僱員的薪水,這樣的設計就不容易理解。僱員的薪水應該是在僱員表中,依賴於僱員屬性。不一致的依賴會使數據難以訪問,甚至在某些時候,數據訪問路徑可能會發生丟失或者被破壞。
  • 第一範式:
    • 1. 消除單個表中重複的屬性。
    • 2. 爲每一組屬性建立單獨的表。
    • 3. 使用主鍵標識每一組屬性。
不要在單個表中使用多個字段來存儲相似的數據。以下的例子:

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

  • 第二範式:
    • 1. 對於可應用於多個表的屬性,建立單獨的表來保存。
    • 2. 使用外鍵對這些表進行關聯。

表中的數據只應該依賴於表的主鍵。例如在財務系統中客戶的地址, 會在客戶,訂單,發貨,發票,收賬的環節都須要。所以應該將客戶的地址放在單獨的一個表中,好比客戶表或者地址表。而不是將它在以上每個表都保存一份。繼續上面的例子,雖然已經知足第一範式,但注意到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

  • 第三範式:
    • 1. 消除不依賴於主鍵的屬性。
表記錄中若是某個屬性並不直接依賴於表的主鍵,那麼這些屬性應該被拿出來,單獨放在一個表中。在上面的例子中student表中, Adv-Room (the advisor's office number) 是函數依賴於Advisor,而非student,所以須要將Adv-Room 屬性放入另外的表中,以知足第三範式。

Student:
Student Advisor
----------------------------------
1022 Jones
4123 Smith

Faculty: Name Room Dept ----------------------------------------- Jones 412 42 Smith 216 42

相關文章
相關標籤/搜索