數(shù)據(jù)庫設計中的字段設置

A.字段類型介紹

不同的關系型數(shù)據(jù)庫在字段類型的具體化上差異較多,這里無法一一詳述,但具體化的字段類型再多,無外乎幾種:字符、數(shù)字、日期、二進制。

下面有三張截圖,前兩張是一張典型的用戶表結構,上面的是PD中的PDM,下面的是導入到MySQL的具體表結構,第三張截圖是SQLServer數(shù)據(jù)庫中的一張用戶表的結構圖:


具體到某個數(shù)據(jù)庫的某個具體類型,這里無法詳述其適用情況,本模塊只制定通用的字段設置規(guī)范。

B.不為空默認值

表中應該盡可能避免可為NULL的列,且盡可能顯示設置默認值,尤其是被索引的列。

在MySQL數(shù)據(jù)庫中,空值是不占用空間的,而NULL其實是占用空間的。再者,MySQL表的列中包含NULL的話,該列就不會包含在索引中,也就是說使用索引是無效的,現(xiàn)在不確定其它數(shù)據(jù)庫是否也是如此。所以考慮今后可能會使用索引的字段,就要設置字段屬性是NOT NULL。比如,如果某個字段后面可能會作為查詢關鍵字使用LIKE的形式進行搜索,就要將該字段定義成索引以提高查詢速度,那這個字段屬性就是NOT NULL的。

除以下數(shù)據(jù)類型的字段外:timestamp、image、datetime、smalldatetime、uniqueidentifier、binary、sql_variant、binary、varbinary,表字段應盡可能顯示設置默認值。建議數(shù)值型的默認值為數(shù)值0,布爾型的默認值為數(shù)值1(通常情況下,系統(tǒng)中所有邏輯型中數(shù)值0表示為“真”、“正常的”;數(shù)值1表示為“假”、“異常的”,這種編碼后面還會有介紹),datetime、smalldatetime類型的字段沒有默認值,必須為NULL。

如果數(shù)據(jù)庫中某個字段有默認值,那么覺得在程序開發(fā)過程中,對應實體類的屬性應該設置同樣的初始化值才合理,記得動軟代碼生成工具中的框架就是這樣設置。之前自己的程序設計中沒有注意到這點,自動生成的所有實體類的屬性都沒有默認值。

注意區(qū)分NULL和空字符串是不同的,數(shù)值型字段中NULL和0更是兩碼事。如果在數(shù)據(jù)庫設計過程中不允許出現(xiàn)NULL字段還好,但如果有允許NULL而沒有設置默認值的字符型字段,程序對記錄執(zhí)行了寫空字符串動作和壓根未執(zhí)行寫動作是兩碼事;如果有允許NULL且設置默認值為空字符串的字段,則無法做這種區(qū)分。當然,通常情況下,我們認為文本框中空字符串的提交動作等同于未執(zhí)行寫入。有些類似的情況是,在程序開發(fā)中,一個空的List對象,或者一個new出來的空對象,和NULL也是不同的,要注意。

像訂單(會診單)這種表,取消、退回、安排這些字段的信息都不是必須有的,可以分流到子表中存儲,放在一張表中會導致出現(xiàn)很多可為NULL或空值的列。之前并不贊成這種過分分流的方法,因為這會另信息的維護變得麻煩,如再有類似情況,應該根據(jù)實際綜合判斷取舍。也要在設計時盡可能遵守第二、三范式,非主屬性完全依賴于碼(主鍵)、消除傳遞依賴,不要讓某張表過分臃腫。

C.類型長度設置

當字段定義為字符串類型時建議使用varchar而不用nvarchar以節(jié)省空間,通常情況下,都要用盡量少的存儲空間來存儲一個字段的數(shù)據(jù),能用int類型的就不用char類型,能用char類型就不用varchar類型,能用varchar(20)的就不用varchar(25)。char和varchar長度設計需要根據(jù)業(yè)務實際需要進行長度控制,禁止預留過長空間。比如主鍵要求用UUID,那就統(tǒng)一為char(32),可以固定的部分就都固定下來。varchar類型雖然根據(jù)實際長度進行存儲,但內存分配則是根據(jù)指定長度,不合理的長度設計會導致內存的不合理占用。

varchar是變長存儲,字段長度是數(shù)據(jù)庫一種約束,定義合理的長度也可以讓人容易理解字段的用途。MySQL中定義的長度如果小于255,字段長度用1個字節(jié)表示,如果超過255,字段的長度將固定用2個字節(jié)表示。Oracle沒有這樣的問題。字段定義的長度對索引也有較大影響,MySQL數(shù)據(jù)庫索引存儲的長度都是定義的長度,不是實際字符的長度,這是一個非常大的問題,估計主要原因是為了實現(xiàn)簡單,所以MySQL在索引上會浪費大量的空間保存字符串。

前臺、程序以及數(shù)據(jù)庫各部分之間對字段大小的限制務必處理恰當,為了節(jié)省存儲空間,選取的數(shù)據(jù)庫字段容量在一定范圍內應該盡可能小,而為了對程序提供更好的擴展支持,又應該盡可能的設置大些,具體字段類型、字段長度如何設置,根據(jù)實際情況取得均衡。而后臺程序部分,對數(shù)值大小長度應該做好校驗處理,確保插入數(shù)據(jù)庫的值大小長度不要超過限制。同時前端也應該給出明確的校驗提醒,讓用戶按提示輸入,決不允許不提醒用戶而擅自把數(shù)據(jù)處理后插入數(shù)據(jù)庫中(這種錯誤真有人犯過)。這樣,前端、程序、數(shù)據(jù)庫全方位校驗處理,自然可以保證數(shù)值的準備性、存取的合理性。

除非要保存文章內容,text字段盡量少用,如果要用能拆到冗余表中最好。禁止使用blob類型保存大文本、附件、圖片等,對于圖片、文檔等附件數(shù)據(jù)庫中只保留原始文件名和存儲路徑。網(wǎng)上也有建議使用其他存儲方式的,比如TFS、SFS等,可以參考。

禁止使用float、double類型,建議使用decimal替代。decimal(a,b),a指定指定小數(shù)點左邊和右邊可以存儲的十進制數(shù)字的最大個數(shù),最大精度38。b指定小數(shù)點右邊可以存儲的十進制數(shù)字的最大個數(shù)。小數(shù)位數(shù)必須是從0到a之間的值。默認小數(shù)位數(shù)是0。比如decimal(5,2)規(guī)定了存儲的值將不會超過5位數(shù)字,并且小數(shù)點后面有2位數(shù)字。

D.Oracle的CLOB

在Oracle中,CHAR為定長字符串,最長2000字節(jié)。VARCHAR2為變長字符串,最長4000字節(jié)。NCHAR和NVARCHAR2分別與CHAR和VARCHAR2相對應,但存儲的數(shù)據(jù)為NLS字符。

目前VARCHAR是VARCHAR2的同義詞。工業(yè)標準的VARCHAR類型可以存儲空字符串,但是Oracle不這樣做,盡管它保留以后這樣做的權利。Oracle自己開發(fā)了一個數(shù)據(jù)類型VARCHAR2,這個類型不是一個標準的VARCHAR,它將數(shù)據(jù)庫中VARCHAR類型的列可以存儲空字符串的特性改為存儲NULL值。如果你想有向后兼容的能力,Oracle建議使用VARCHAR2而不是VARCHAR。

在Oracle中沒有TEXT類型,但有用于大文本存儲的CLOB類型。Clob是指大字符對象,也就是英文Character Large Object的縮寫;Blob是指二進制大對象,也就是英文Binary Large Object的縮寫;由此可見這兩個類型都是用來存儲大量數(shù)據(jù)而設計的。

LONG最大存儲2G字符數(shù)據(jù),但現(xiàn)在已不推薦使用(改用CLOB);CLOB在Oracle 9i及以前,最大可存儲4G字符數(shù)據(jù),在Oracle10g及以后,最大可存儲4G*數(shù)據(jù)庫塊大小的字符數(shù)據(jù);NCLOB基本同CLOB,就是存儲的數(shù)據(jù)為NLS。

在Oracle數(shù)據(jù)庫表中使用CLOB類型字段,最大的問題是備份數(shù)據(jù)時不好處理。在有些情況下,給政府、企業(yè)做項目,只給你Oracle的訪問權限,而不給你Oracle所在服務器的操作權限,也就是說自己無法操作Oracle服務端工具。但Oracle的客戶端中又沒有exp、expdp命令,這樣備份導出數(shù)據(jù)庫就不好弄了(此處不提溝通協(xié)調甲方處理)。SQL Developer是Oracle的官方工具,用其導出數(shù)據(jù)庫,如果導出的是SQL格式,那CLOB類型字段的數(shù)據(jù)將直接被忽略——這絕對是無法接受的。官網(wǎng)上有文章說可以將數(shù)據(jù)庫導出為loader或pdf格式,自己嘗試導出這兩種格式,發(fā)現(xiàn)不能導出成單個文件,會導出很多的文件。而且導入時也需要用到額外的工具——Oracle服務端的sqlldr.exe,這樣只借助客戶端也是不行的。

在SQL Developer“工具”菜單下,還有兩個選項:“數(shù)據(jù)庫Diff”及“數(shù)據(jù)庫復制”,如果所處網(wǎng)絡可同時訪問源數(shù)據(jù)庫和目標數(shù)據(jù)庫,可用這種方法互相拷貝數(shù)據(jù),但是同樣的問題,這種數(shù)據(jù)庫復制方法,仍然是不能處理COLB、BLOB的字段。而且我發(fā)現(xiàn),凡是帶有這兩種字段的表,在復制時都沒有數(shù)據(jù),不是相應字段沒有數(shù)據(jù)、是整個表的數(shù)據(jù)都沒有復制,其它沒有BLOB、CLOB字段的表,數(shù)據(jù)拷貝都正常。

也曾想使用的PL/SQL Developer工具進行備份,導出了PL/SQL Developer自己的格式(pde)??墒菂s提示stream read error,到網(wǎng)上一查,原來PL/SQL Developer自己的格式也是不支持COLB、BLOB類型字段的導出的。

之前同事介紹過Navicat for Oralce工具,但其在導出CLOB、BLOB類型的字段時,如果字段中的數(shù)據(jù)過長,也是無法再正常導入的。這個小工具看似簡單輕巧,在執(zhí)行一些操作時問題卻很多,不宜作為一款常用的Oracle管理工具。

這樣看來,只有expdp命令才能有效導出clob、blob格式的字段了。

不過,如果你雖然沒有源數(shù)據(jù)庫服務端的訪問權限,卻有目標數(shù)據(jù)庫服務端的訪問權限,且兩個庫可在一個網(wǎng)絡中訪問,也是有辦法用EXP命令備份源數(shù)據(jù)庫的。就是讓目標數(shù)據(jù)庫服務端的TNS監(jiān)聽源數(shù)據(jù)庫的實例,再利用目標數(shù)據(jù)庫Oracle服務端的exp.exe工具遠程導出源數(shù)據(jù)庫,導出導入命令和上面類似:

此外,用PL/SQL Developer工具備份數(shù)據(jù)時,Export User Objects菜單命令導出的是SQL文件,在這里你可以將建表、序列、觸發(fā)器、存儲過程等的SQL語句全部導出成一個文件,但是這里面并不包括數(shù)據(jù)。要想導出數(shù)據(jù),必須用Export Tables……菜單命令,導出DMP文件。當然也可以導出其它格式的文件(SQL、PDE),但建議用DMP格式,因為前面已經(jīng)說過,如果表中有CLOB類型字段的話,用其它格式的導出方式恐怕有問題。

如果一個表不存在,而這個表中沒有CLOB、BLOB這種特殊數(shù)據(jù)類型的字段,用DMP導入數(shù)據(jù)時PL/SQL會自動建立這個表。但如果一個表不存在,而這個表中又有CLOB、BLOB這種特殊字段,直接導入DMP格式的文件會報錯IMP-00003:遇到ORACLE錯誤959。所以在Oracle中導入數(shù)據(jù)庫時應該先執(zhí)行用Export User Objects導出的SQL文件,這樣相關的序列、觸發(fā)器、表結構都已經(jīng)建好了,再導入用Export Tables……導出的DMP文件,也就是導入其中的數(shù)據(jù),就萬全了。

E.數(shù)值類型選擇

float:浮點型,含字節(jié)數(shù)為4,32bit,數(shù)值范圍為-3.4E38~3.4E38(7個有效位)

double:雙精度實型,含字節(jié)數(shù)為8,64bit數(shù)值范圍-1.7E308~1.7E308(15個有效位)

decimal:數(shù)字型,128bit,不存在精度損失,常用于銀行帳目計算。(28個有效位)

float和double的相乘操作,數(shù)字溢出不會報錯,會有精度的損失。當對decimal類型進行操作時,數(shù)值會因溢出而且報錯。

Oracle中的數(shù)值類型,Oracle只是在語法上支持decimal類型,但是在底層實際上它就是NUMBER類型,支持decimal類型是為了能把數(shù)據(jù)從Oracle數(shù)據(jù)庫移到其他數(shù)據(jù)庫中(如MySQL、DB2等)。Oracle的NUMBER數(shù)據(jù)類型的精度:NUMBER(P,S),P:1---38,S:-84---127。S代表的是小數(shù)位數(shù),P代表的是總位數(shù)(整數(shù)位數(shù)和小數(shù)位數(shù))。所以,平時如果在Oracle中用自增主鍵,長度設為NUMBER(10)的話,相當于NUMBER(10,0),表示最高可記錄到十億級的數(shù)據(jù)量。

下圖是MySQL中的整數(shù)型數(shù)值類型詳述:

F.通用字段處理

日期時間類型字段,網(wǎng)上有建議,采用int來記錄unix_timestamp,自己還是習慣用datetime。不過設計原則是粒度越小越好,所以這里要求日期時間類型的字段,盡可能精確到時分秒,用datetime類型。即便是像生日(birth_date)這種字段,一般只存儲到年月日,但在選擇字段類型時建議還是用datetime而非date,以防萬一。如有部分時間字段著實無須記錄到時分秒,則用date類型。嚴禁使用varchar等字符串類型記錄日期時間,更不要把時間猜分,年在單獨的字段、月在單獨的字段、日又是單獨字段,老實講TM想不明白這種人的設計思路是什么樣的。

網(wǎng)絡IP字段,網(wǎng)上有建議,除特殊情況一律用bigint來記錄inet_aton值,但這種存儲方式貌似只在MySQL中適用,這里要求還是用varchar存儲。關于inet_aton想了解的話可以看下參考文獻中的“MySQL的IP處理函數(shù)inet_aton()和inet_ntoa()”。

字典編碼字段,之前在SQLServer中設計數(shù)據(jù)庫時統(tǒng)一使用char(2)類型,Oracle數(shù)據(jù)庫中統(tǒng)一使用number(2),在MySQL中統(tǒng)一使用tinyint(2)?,F(xiàn)在想來最合理的還是設置為tinyint(2),以后數(shù)據(jù)庫字典編碼字段統(tǒng)一按此設置。就是Oracle中沒有tinyint類型,不知道如果在PD中設置此種類型,導入到Oracle時會自動轉換處理還是直接報錯。

備注字段,盡可能在所有表中都保留這個字段,也是給前端信息錄入預留一個可擴展部分。統(tǒng)一命名為remark,字段類型為varchar(200),最多100個中文字符。再多的話說明有額外信息,就不適合放在備注字段中了,要再加新字段存儲。

排序字段,不是每個表中都需要額外的排序字段,但有些表這必須有,比如記錄菜單信息的表、門戶網(wǎng)站中存放文章內容的表等。這里推薦統(tǒng)一使用int(10)做為所有表中的排序字段類型。

字段設置部分撰述內容較多,相對詳細,這是比較重要的一部分。以后的數(shù)據(jù)庫設計,字段類型選擇、字段長度設置部分都要以此為依據(jù)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容