1、引言
數據庫設計過程中表、字段等的命名規范也算是設計規范的一部分,不過設計規范更多的是為了確保數據庫設計的合理性、為了項目最終的協調穩定性,而命名規范則更多的是為了確保設計的正式和統一。公正的講,數據庫中表字段等等以什么樣的方式命名、取具體什么名字,并不會直接影響到項目的穩定性,不是說叫黑貓項目就是正常的,叫白貓就運行異常了。
制定規范的直接目的是約束設計行為,最終目的是確保設計的合理統一。規范雖然是有豐富項目經驗的人制定的,但維護的卻不是某個人的意志,而是項目的意志,因為遵守此規范對項目是好的有利的,此規范才有意義。所以規范是為了項目利益最大化而在團隊人員中形成的一種約定(貌似約定的英文單詞Convention本身就有規范的意思),所有參與設計的人員都要遵守此約定,所有參與開發的人員都會依此約定解讀設計。我們約定,所有的主鍵統一命名為id,結果有設計人員違反約定將一個非主鍵字段命名為id,約定被打破,共識也就被打破,設計人員之間、開發人員與設計人員之間的溝通就出現了隔閡。
設計規范更多的是為了合理,命名規范更多的是為了統一,團隊協作中,統一在某種程度上比局部設計開發的好壞更重要。違反了約定,局部設計開發的再好,反而可能影響到項目整體的穩定協調。
約定優先于配置(Convention Over Configuration)。
在“設計規范”中提到過一些命名規范,也詳細講述了表、字段的類型、注釋等屬性的設置,為什么要求主鍵統一命名為id、統一為char(32)類型,為什么要求浮點型數值統一為decimal類型?我們希望團隊中所有人看到設計成果,一眼就可以明白這個字段是做什么的、代表的含義是什么,可以但不止于見名知意。再者,當前的開發模式,前后端代碼及數據庫文檔、程序文檔、接口文檔等等大都是由工具生成,而其最底層的依據就是數據庫,表、字段的命名注釋同時會影響到工具生成的文檔、代碼中的類屬性方法甚至是前臺頁面的命名注釋,數據庫設計命名的規范關系到整個項目的規范。
命名規范會分四個大模塊來介紹:基本規范、名大小寫、具體規范、特別說明,各大模塊下面有的會有子模塊特別說明。
2、基本規范
A.可用字符
數據庫、表、字段等所有名稱的可用字符范圍為:A-Z,a-z,0-9和_下劃線,除此外不允許使用其它字符作為名稱。數據庫及表名均不允許出現數字,字段名除非特殊情況不允許出現數字。
在前面介紹關系范式時曾提到過一個破壞范式的例子:平時的多圖片上傳功能,可能只設計一個字段存儲圖片名稱,這樣字段值中就會包含多個圖片的名稱,里面用|或其它符號分隔。像這種情況,其實也可以設計成三五個字段image_name1、image_name2、image_name3……分別存儲,然后限制可上傳圖片個數,這就是字段名中可出現數字的特殊情況——雖然也不建議這樣設計或取名。
B.命名方式
數據庫、表、字段等所有名稱使用英文單詞或英文短語或相應縮寫,禁止使用漢語拼音,且均使用單數名,例如:對存儲客人信息的表命名為customer而不是customers。名稱應該清晰明了,能夠準確表達事物的含義,遵循見名知意的原則。
Oracle表、字段等名稱統一使用大寫,單詞間用下劃線分隔;SQLServer數據庫、表等名稱采用Pascal命名法,字段名稱采用Camel命名法,大小寫字母混排;MySQL數據庫、表、字段等名稱統一使用小寫,單詞間用下劃線分隔。至于為何這樣規定,下一個模塊會有詳細介紹。
Oracle相對特殊,通常的操作順序是,先創建數據庫實例,然后創建表空間,然后創建用戶并設定此用戶的默認表空間,最后在此用戶下建表。多數情況下我們都是只建一個實例,然后在此實例下建不同的表空間、不同的用戶,根據不同的用戶來區分不同的庫。關于實例、表空間及用戶的命名方式并無限制,可以采用大小寫混排,也可以只用大寫或小寫,但對于表和字段,我們要求統一為大寫。
我們要求統一為大寫或小寫的名稱,兩個單詞間用_下劃線分隔,SQLServer使用Pascal或Camel方式命名。這些不僅僅是為了數據庫設計的可讀性,也是為了最終生成代碼的可讀性。這里簡單介紹下編程中常用的三種類、變量、函數等的命名方式:
a.匈牙利命名法。由微軟的一位匈牙利程序員Charles Simonyi提出,相對復雜,首字母小寫,基本原則是:變量名=屬性+類型+對象描述,其中每一對象的名稱都要求有明確含義,可以取對象名字全稱或名字的一部分。匈牙利命名法主要在C或C++這種面向過程的程序語言中使用,如果用在Java、C#這種面向過程的語言中就很別扭。
不過自己在寫Web前端頁面或腳本時,借用了這種命名方式,form表單中涉及的常用HTML標簽不外乎如下幾種:label、text、button、submit、password、textarea、radio、checkbox、select等,那我在給表單元素命名或者說是給id或name賦值時,就會將元素類型做前綴,例如用戶名輸入框為textName、性別單選按鈕名為radioGender。這樣做的好處是我在編寫腳本時,根據id或name名稱一眼就可以看出這個表單元素是什么類型。在修改頁面中初始化表單數據時我可以直接遍歷表單元素、根據元素名稱判斷出元素的類型進而采用適當的賦值動作,而不用逐個選擇元素去賦值。
在ASP.NET編程中,如果使用微軟的服務器控件,在命名時我會用控件類型做名稱后綴,例如Name_TextBox、Gender_RadioButtonList等。之所以不再將類型做前綴,一來是VisualStudio本身默認的服務器控件命名方式即時如此,控件類型做后綴;二來是因為服務器控件的類型名稱太長,而自己又不愿用縮寫,因為沒必要,VisualStudio的提示功能強大,后綴的長度不會影響到編程速度。
b.Camel命名法。即駱駝式命名法,首字母小寫,采用該命名法的名稱看起來就像駱駝的駝峰一樣高低起伏。Camel命名法有兩種形式:
第一種是混合使用大小寫字母,例如englishName、fartherCode。在Java中,屬性名和方法名一般都采用這種命名方式,在C#中只有屬性名采用這種命名方式,我們在前面也規定,SQLServer中字段的命名也采用這種方式。
第二種是單詞之間加下劃線,例如english_name、farther_code。我們在前面規定,Oracel和MySQL表、字段的命名都采用這種方式,不過我們要求Oracle全部使用大寫字母,MySQL全部使用小寫字母。再者,無論是在Java還是C#,甚至是在JavaScript中,所有的常量,都使用這種命名方式,但和Oracle表字段的命名方式一樣要全部使用大寫字母,比如前面的設計規范中介紹數據字典表時,字典類型、字典項的編碼和文本信息需要即時獲取,以往的習慣在程序中建立一個常量類,所有用到的字典數據在里面用常量標明,這時常量的命名方式即是如此。
c.Pascal命名法。即帕斯卡命名法,與Camel命名法類似,不過是首字母大寫。在C#中,類名和方法名一般采用這種命名方式,在Java中類名一般采用這種方式。在前面也規定,SQLServer中數據庫、表的命名也采用這種方式。
除數據庫的設計外,不同編程語言、前端HTML標簽、JavaScript腳本、樣式等等部分都會涉及命名的問題,如果細細整理,項目開發中每個子模塊的命名規范都夠再出一份長篇文檔的。這里只簡單介紹下三種常用的命名方式,其它部分的命名方式只是一提,重點還是在數據庫的命名規范上。前面說過多次,程序、文檔甚至前端頁面有大部分通過工具自動生成,只有數據庫嚴格按要求來命名,才能根據不同的編程語言編寫不同的代碼模板,統一控制生成部分各處的命名方式。比如,我們要求在MySQL數據庫中,表名都使用小寫,單詞間用下劃線分隔,交易記錄表名稱為trade_log,那可以設定生成規則,對應生成的實體類名就是TradeLog,對應生成的Dal層就是TradeLogDal,對應的Service名就是TradeLogService,等等。可如果設計沒有規范、不統一,那文檔生成規則、代碼生成規則、程序編寫規則等等也就無法統一制定了。
C.長度限制
關于各種數據庫管理系統(DBMS,Database Management System)本身對表、字段等名稱的長度限制如下:
以上是從網絡整理而來,Oracle、SQLServer及MySQL的限制長度親自測試過。但也有說因為數據庫和表的名字可能對應于目錄和文件名,故而服務器運行的操作系統可能強加額外的限制。不過除了Oracle的限制長度過短外,其它的一般不會被超出。我們希望名稱盡可能詳細準確的表達事物含義,但如果過于冗長,就會給操作及后面的程序編寫帶來諸多不便。
D.單詞縮寫
自己以往設計數據庫時,經常頭疼于表、字段的命名,一來找不到好的單詞去表述,二來有時可能涉及多個單詞,導致名稱過長。字段名過長帶來的不便有限,最終影響的不過是程序實體類中的一個屬性,可如果表名也過長,就比較麻煩了,生成的程序各層間針對此表的類名、變量名都可能受到影響,給后期的編寫帶來很大不便。使用單詞縮寫又拿不準,找不到合適的縮寫方式。這里建議當表名超過15個字符、字段名超過20個字符時就應該嘗試用單詞縮寫重新命名,如果名稱長度在此之內,原則上講則盡可能不用縮寫以使表述具體清晰,表、字段最終的名稱長度要嚴格控制在30個字符以內。關于單詞縮寫規則如下:
a.如果可以在字典里找到一個詞的縮寫,就用這個做為縮寫,比如:Monday=Mon、December=Dec,可在此網站下查找到一些英文單詞的縮寫:http://shortof.com/;
b.可以刪除單詞元音(詞首字母除外)和每個單詞的重復字母來縮寫一個單詞。比如:Current = Crnt、Address = Adr、Error = Err、Average = Avg;
c.對于主從表,如果主表名稱沒有縮寫而從表的名稱需要縮寫,則從表名稱從第二個單詞開始縮寫,第一個名詞盡可能和主表保持一致。比如企業基本信息表名稱為enterprise,則企業訴訟表enterprise_litigation可簡寫為enterprise_ltg,企業證書表enterprise_certificate可簡寫為enterprise_crt。最終的數據庫表及由數據庫表生成的程序在集成開發環境(IDE,Integrated Development Environment)中是按名稱排列的,這樣做是為了讓相似功能的表、類文件排列在一起,方便開發者操作。
更詳細的單詞縮寫規則介紹可以參考文檔末尾的參考文獻。
3、名大小寫
理想情況下所有關系型數據庫對于表名、字段名、字段內容等大小寫的處理會有個大一統的方式,比如要求所有都是大小寫敏感的,可實際的情況卻是,不同的數據庫及同一數據庫在不同的操作系統下對大小寫的處理都是不同的。以往筆記中記錄的第一次遇到數據庫處理大小寫的問題是,做的一個登錄頁功能,測試人員發現輸入用戶名MengXianzhi或mengxianzhi均可以正常登錄,但數據庫用戶表里只有一條用戶名為MengXianzhi的記錄,當時用的是SQLServer數據庫。
A.編碼和字符序的介紹
在前面介紹數據庫編碼時曾經提到,如果使用MySQL Workbench創建新的數據庫,會要求選擇Collation。Collation的字面意思是字符序,用于指定數據集如何排序、及字符串間的比對規則。可字符本來是不分大小的,這樣對字符的>、=、<操作就需要有個字符序的規則。Collation做的就是這個事情,你可以對表進行字符序的設置,也可以單獨對某個字段進行字符序的設置,優先級從高到底可分為四種:服務器層、數據庫層、表層、字段層,真正決定性因素是在字段層,如果沒有指定則默認從上一層繼承過來:字段層繼承表層,表繼承數據庫層,數據庫層繼承服務器層,服務器層則需要設置,如果不設置默認為latin1_general_ci。
平時我們說的設置MySQL編碼為gbk、gb2312、utf8或lantin等指的是字符編碼,也就是Character Set。當表的Character Set是lantin1時,若字段類型為nvarchar,則字段的字符集自動變為utf8。
可見數據庫、表、字段的Character Set可逐級覆蓋,這有點像上面說的四種字符序設置方式間的優先級關系。本規范中建議數據庫統一設置編碼為utf8,不僅僅是為了應付數據庫間導入導出過程中、因編碼格式不統一而導致的惱人的亂碼問題,也是因為utf8是一種萬國碼(Unicode)。軟件的國際化是大趨勢,而Unicode是國際化最佳的選擇。在MySQL中有兩個支持Unicode的Character Set:第一個是UCS2,使用16 bits來表示一個Unicode字符;第二個是utf8,使用1~3 bytes來表示一個Unicode字符。
那字符編碼(Character Set)和字符序(Collation)之間的關系是什么呢?
每個Character Set會對應一定數量的Collation,在MySQL命令窗口中輸入Show Collation;命令可以查看到所有字符序及其所屬的字符編碼列表:
同一個Character Set的不同Collation的區別在于排序、字符集對比的準確度以及性能,這里的準確度是指相同兩個字符在不同國家語言中的排序規則可能是不同的,性能是指排序以及比對速度。例如:utf8_general_ci在排序的準確度上要遜于utf8_unicode_ci,當然,對于英語用戶應該沒有什么區別,但性能上要略優于utf8_unicode_ci,例如前者沒有對德語中? = ss的支持。而utf8_danish_ci相比utf8_unicode_ci增加了對丹麥語的特殊排序支持。
Collation名字的規則可以歸納為兩類:
CI是Sensitive的縮寫,即指定數據庫對大小寫是否敏感。MySQL中Character Set對應的Collation多是CI的,CS這種校驗字符已經逐漸被淘汰,gbk、gb2312、utf8等編碼的所有Collation沒有一個是CS的。Bin表示用二進制存儲數據,用編碼值進行比較,區分大小寫。
在上面的截圖中也可以看到,gb2312編碼默認的Collation是gb2312_chinese_ci、gbk編碼默認的Collation是gbk_chinese_ci、utf8編碼默認的Collation是utf8_general_ci。按本文檔中的規范,建議所有編碼統一設置為utf8,如果不單獨設置Collation,則按默認的utf8_general_ci,字段值是不區分大小寫的。
那在字符序為CI的情況下,如何在執行SQL查詢時區分字段值的大小寫呢?假設用戶表user中有兩個用戶:MengXianzhi和mengxianzhi,當我們執行如下查詢時會得到兩條記錄:
select * from userwhere user_name = 'MengXianzhi';
如果要區分大小寫,有下面兩種方式可以精確查詢:
select * from userwhere binary user_name = 'MengXianzhi';
select * from userwhere user_name = binary 'MengXianzhi';
推薦使用第二種查詢方式,這樣可以保證當前字段的索引依然有效,而第一種會使索引失效。其實個人更傾向于建議統一設置數據庫默認的Collation為utf8_bin,也就是對大小寫敏感。程序中針對數據庫字段內容的比對查詢處處都是,英文內容存儲也處處都有,如果所有相關查詢語句都加binary關鍵字,太過麻煩,不如在數據庫中統一設置,這樣也不會出現在本章節開頭所描述的問題了。
如果不想在數據庫中統一設置,也可以只針對表、字段單獨設置,但非常不建議如此,因為這會導致局部配置和全局配置相悖。一直堅持規范、約定、配置等盡可能采用大一統的方式,除非不得以。開放局部配置會導致配置的多樣性,不利于統一管理維護,不過下面還是會簡單介紹下局部配置的方法。
B.編碼和字符序的設置
這部分會分別對比MySQL、SQLServer、Oracle三種關系型數據庫的字符編碼和字符序配置,先從MySQL開始。
在MySQL中,自己沒有找到從服務器層面直接配置Collation的方法,但是數據庫、表及具體字段設置Collation的方法都有。再就是在PD中未能找到全局設置Collation的方法,只找到了具體到某一字段設置的地方。截圖如下,最后一張是PD中對某一具體字段進行配置的方法:
如果要直接更改某一個數據庫的Character Set或Collation可以在MySQL Workbench中做如下設置:
其實Character Set和Collation本就是一體的,所以其實都是在這一個地方設置,兩種選項對應的SQL語句就是:
ALTER SCHEMAbsctelmed
DEFAULT CHARACTER SET utf8 ;
ALTER SCHEMAbsctelmed
DEFAULT CHARACTER SET utf8DEFAULT COLLATE utf8_bin ;
在SQLServer 2008中,只找到了從數據庫層及具體字段層面直接配置Collation的方法,但是從表層面中的配置卻沒有。和MySQL一樣,在PD中未能找到全局設置Collation的方法,只找到了具體到某一字段設置的地方。截圖如下,最后一張是PD中對某一具體字段進行配置的方法:
如果想查看SQLServer的版本、字符序等相關信息也可以用如下SQL語句:
SELECT
SERVERPROPERTY(N'Edition')AS Edition,
SERVERPROPERTY(N'ServerName')AS ServerName,
SERVERPROPERTY('ProductVersion') AS ProductVersion,
SERVERPROPERTY('ProductLevel')AS ProductLevel,
SERVERPROPERTY('ResourceVersion')AS ResourceVersion,
SERVERPROPERTY('ResourceLastUpdateDateTime')AS ResourceLastUpdateDateTime,
SERVERPROPERTY('Collation')AS Collation;
直接在SQL Server Management Studio圖形化界面中更改SQLServer的字符集可能會出現問題:
這時可通過如下更改語句進行更改:
ALTER DATABASEHealthManagement COLLATE Chinese_PRC_CI_AS
在Oracle中貌似沒有Collation的概念,又或者是換了另外一個概念來進行類似的設置?在PD中具體到表字段的Oracle選項卡中也沒有字符集相關的配置:
Oracle中默認是嚴格區分字段內容大小的,如果不想對大小寫進行區分可以使用Lower()或Upper()函數來達到目的,也可以使用NLSSORT()函數,覺得這個函數就和MySQL中的Collation設置所達到的效果相似。如下三個SQL語句所達到的效果是一樣的:
select * from userwhere user_name = 'MengXianzhi' COLLATE Latin1_General_CI_AI;
select * from userwhere Upper(user_name) = Upper('MengXianzhi');
select * from userwhere NLSSORT(user_name,'NLS_SORT = Latin_CI') =NLSSORT('MengXianzhi','NLS_SORT = Latin_CI');
但是不清楚上面第三種寫法,如果不是精確查詢,而是模糊查詢,用like關鍵字,查詢語句如何下,嘗試下面的寫法,好像不起作用:
select * from userwhere NLSSORT(user_name,'NLS_SORT = Latin_CI')like NLSSORT('Meng','NLS_SORT = Latin_CI')+"%";
Oracle9i之前,中文是按照二進制編碼進行排序的,而在Oracle9i中新增了按照拼音、部首、筆畫排序功能,使用方法如下:
按漢字拼音排序:SELECT * FROM USER ORDER BY NLSSORT(user_name ,'NLS_SORT =SCHINESE_PINYIN_M')
按漢字筆劃排序:SELECT * FROM USER ORDER BY NLSSORT(user_name ,'NLS_SORT =SCHINESE_STROKE_M')
按漢字部首排序:SELECT * FROM USER ORDER BY NLSSORT(user_name ,'NLS_SORT =SCHINESE_RADICAL_M')
注意,我雖然嚴格測試過MySQL、SQLServer和Oracle三種不同關系型數據庫針對CharacterSet和Collation設置的區別,但對于同一數據庫的不同版本間的區別卻未深究。各種關系型數據庫總是在不停升級,某些升級可能會導致新舊版本間差異巨大,而本文檔中所述細節又甚多,所以具體到實際情況,某些地方出現不同也很正常。
C.由此引出的亂碼問題
Character Set和Collation并不僅僅影響到數據庫存儲內容的大小寫敏感問題,還會影響到數據庫操作中常見的亂碼問題。這里既然提到了,所以簡單講下。
以往負責的項目較為雜亂,所以對各種常見關系型數據庫多有接觸,就自己的經驗,亂碼問題出現最多的是MySQL數據庫,尤其是早期版本的MySQL,其次是Oracle,SQLServer當然也有,但相對少。亂碼問題可以分為以下幾種:
a.不同類型的關系型數據庫間、數據互相導入導出,導致的中文數據亂碼。
比如將MySQL中的數據導入到SQLServer,將SQLServer中的數據導入到Oracle。這種情況其實相對少見,因為一般數據操作都是在同一類型的數據庫間進行。遇到這種情況時,數據間的導入導出一般都有中間過程,比如先從源數據庫中將數據導出成CSV文件,然后再將CSV文件導入到目標庫。又或者是,借助目標數據庫的管理工具,直接連接源數據庫進行導入。也有將源數據庫中的數據導出成SQL文件,然后對SQL文件進行一定更改后在目標數據庫中執行的。
b.類型相同、版本不同的關系型數據間的數據導入導出,導致的中文數據亂碼。
c.類型相同、版本相同的關系型數據間的數據導入導出,導致的中文數據亂碼。
d.針對Oracle,客戶端版本和服務端版本不同所致。客戶端的版本比較新、而服務端比較舊,或者是客戶端為32位的而服務端是64位等箸。
e.主要也是針對Oracle,客戶端和客戶端所在操作系統不協調、服務端和服務端所在操作系統不協調。比如操作系統為32位,但下載的客戶端卻是64位的。
f.針對程序,官方管理工具操作數據庫查詢沒有問題,但是程序訪問數據庫查詢出的中文卻是亂碼。
中文亂碼問題在各種數據庫的操作中、在種程序語言各種項目的開發中時常出現,針對以上種種我們建議:
a.安裝及操作數據庫時,編碼相關的默認設置,除非有把握,否則不要隨意更改;
b.項目開發環境、測試環境、模擬環境、真實環境、線上環境的操作系統及數據庫等盡可能統一版本統一配置,選擇和操作系統相匹配的數據庫版本;
c.針對Oracle數據庫,客戶端和服務端盡可能統一版本,盡可能選擇和操作系統相匹配的客戶端及服務端版本;
d.在數據庫日常操作過程中均使用官方的管理工具,或直接在命令行中操作;SQLServer不用說,MySQL我們建議使用MySQL Workbench,Oracle我們建議使用SQL Developer;
e.如果現實情況不方便或不允許達到以上要求,或者雖然按以上要求操作配置數據庫后依舊出現亂碼問題,那就根據實際情況網絡搜索尋求相應解決方案。
遇到具體問題時刻記得Google是第一位的,僅這一項就可以幫我們解決99%的問題。我們的分析討論建議更多的是為了全面了解問題本身,但遇到具體問題如何解決,仍舊要靠自己思考、靠Google的智能搜索。下面的截圖來自于以往筆記,和某一亂碼問題的交鋒:
D.表名字段名等大小寫
上面講字符序的大小寫敏感,針對的都是數據庫表字段值或者說是字段對容,而對于數據庫名、表名、字段名、變量名、執行目錄名等(在執行SQL查詢時)的大小寫敏感呢?
在Linux下MySQL的數據庫名、執行目錄名、表名、表的別名、變量名默認是嚴格區分大小寫的,數據庫名大小寫敏感不可改,執行目錄名大小寫敏感可參數調配(lower_case_file_system),表名大小寫敏感也可參數(lower_case_table_names)調配,但不確定這個參數是否影響表別名及變量名的大小寫敏感。列名與列的別名在所有的情況下均是忽略大小寫的,也不清楚可否參數調配。
MySQL在Windows下數據庫名、執行目錄名、表名、表的別名、變量名、列名、列別名等默認都不區分大小寫。
用root登錄服務器修改/etc/my.cnf配置文件,在[mysqld]節點下,加入一行:lower_case_table_names=1可以另其不再區分表名大小寫。而在Windows系統下,lower_case_table_names參數缺省設置即為1,即不區分表名大小寫。
在SQLServer中自己測試的結果是,數據庫名、用戶名、表名、表別名、列名、列別名默認在執行SQL查詢時均不區分大小寫。SQLServer版本為2008 R2。
在Oracle中自己測試的結果是,實例名、表空間名、用戶名、表名、表別名、列名、列別名默認均不區分大小寫。Oracle為Linux版本,11.2.0.4。
這樣整理之后,如下表格:
內容中的是否表示默認情況下是否大小寫敏感,括號中的(可)表示可參數調配。空白部分表示不確定,或者沒有這一項。
SQLServer和Oracle、MySQL(Windows系統下)雖然同樣默認對表名、字段名等不區分大小寫,但不同的是Oracle及MySQL處理的更嚴謹。通過SQL*Plus、PL/SQL Developer或SQL Devloper在Oracle中建表,默認會自動將表名轉換成大寫后再寫入數據庫。在Windows系統中,默認情況下,建表時MySQL會強制要求所有表名和列名均為小寫。SQLServer雖然在執行SQL查詢時不區分表名、列名大小寫,但在命名及在可視化管理工具中顯示時卻又區分大小寫。也有另外一種可能,目前我測試用的Oracle及MySQL版本比較新,則SQLServer則較舊,最新版的SQLServer或許已經沒有這種問題。
前面說通過SQL*Plus、PL/SQL Developer或SQL Devloper在Oracle中建表,默認會自動將表名轉換成大寫后再寫入數據庫。但實際上Oracle是可以支持大小寫混排的命名方式的,但前提是要在表名外面加雙引號。
仔細查看過,使用PD設計針對Oracle的PDM,如果你的表名全部大寫,那PD在生成SQL建表語句時不會在表名外面加雙引號,可如果你的表名是大小寫混排的,那PD在生成SQL建表語句時會自動在表名外加雙引號,保留這種大小寫混排的命名方式。其實不光是創建表,在Oracle中創建觸發器、序列時也是如此,名字不加引號就不會區分大小寫,加上引號就會區分。
不建議在Oracle中使用大小寫混排的命名方式,原因有很多:
a.當你使用Oracle SQL Developer工具查看表時,點選“詳細資料”選項卡,可能會報錯:執行請求的操作時遇到錯誤,ORA-00904:"STATUS":invalid
identifier。網上搜到ORA-00904錯誤原因和Oracle建表時表名大小寫有關,但不清楚和Oracle版本有沒有關系。
b.如果表列名都區分大小寫,那在建立查詢時表名和列名都應該帶有雙引號,會給后面程序的編寫帶來麻煩。如果使用Hibernate框架,那其生成的查詢是不會帶有雙引號的,會出現無法找到表或視圖的錯誤。
c.使用PL/SQL Developer工具可視化地進行表的刪除等操作時,后臺采用的是不帶雙引號的表名,也會出現無法找到表或視圖的錯誤。這時只能采用類似drop table "tableName"的語法,在SQL*Plus或PL/SQL Developer手工刪除或修改表。
我們在基本規范中為什么要求MySQL的數據庫名、表名、列名等統一為小寫,Oracle中的表名、字段名等統一為大寫,正是基于以上原因。我們希望藉此規定,將命名大小寫規則統一,盡可能的讓數據庫設計不要在名稱大小寫這個問題上多出不必要的麻煩。
這里順便一提,在PD中可以將PDM中的表名或列名統一轉換成大寫或小寫,菜單Tools——Model Options——Naming——Convertion——Table或Column中進行設置。
E.針對大小寫合理建議
個人認為Oracle數據庫對表名、字段名、字段內容等大小寫敏感的默認處理是最合適的,在執行SQL查詢時不區分表名、表別名、列名、列別名的大小寫,但嚴格區分字段內容的大小寫。也正因此,我們在基本規范中建議在Oracle數據庫的設計過程中表、字段等的名稱統一使用大寫,單詞間用_下劃線分隔。
我們在基本規范中建議,MySQL數據庫、表、字段等名稱統一使用小寫,單詞間用_下劃線分隔。同時,我們建議在MySQL數據庫中將Character Set設置為utf8、將Collation設置為utf8_bin,并在數據庫配置文件中設置lower_case_table_names=1,當然,Windows系統中默認就是此種設置,無需再做更改。
我們建議在SQLServer中將排序規則設置為Chinese_PRC_CS_AS,其默認為Chinese_PRC_CI_AS,因為SQLServer數據庫不用考慮部署在不同系統的問題,所以不建議更改除此外的其它編碼、字符序相關的默認設置。我們上面也說過SQLServer雖然在執行SQL查詢時不區分表名、列名大小寫,但在命名及在可視化管理工具中顯示時卻又區分大小寫,為了查看方便所以我們在“基本規范”中要求SQLServer用Pascal的命名方式。
在“名大小寫”這個章節,更多的不是制定規范,而是在講解前面的“數據編碼”、“基本規范”等模塊中列出的一些規范制定的原因。在這里詳細講解了MySQL、SQLServer、Oracle三種數據庫的編碼、字符序相關的配置說明以及表名、字段名、字段內容等大小寫敏感的控制處理等。
4、具體規范
A.關于數據庫的命名
對于數據庫的命名不做特別要求,簡單明了即可,這里主要注意在一個大環境中相似項目的數據庫命名,最好有明顯區分。
這里順帶一提,互聯網公司的數據庫一般分為五個環境:
a.開發環境(Development Environment)。開發可讀寫,開發人員可以修改表結構,可以隨意修改其中的數據;但是需要保證不影響其他開發同事。
b.測試環境(TestEnvironment)。開發可讀寫,部署的測試系統訪問此庫,代測試人員使用。
c.模擬環境(Simulation Environment)。開發可讀寫,通過web平臺,發起上線請求時,會先在這個環境上進行預執行,這個環境也可供部署上線演練或壓力測試使用。
d.線上從庫(Real Environment)。只讀,會實時從線上數據庫同步,不允許修改數據,不允許修改表結構。供線上問題查找,數據查詢等使用。
e.線上環境(Online Environment)。開發人員不允許直接在線上環境進行數據庫操作,如果需要操作必須找數據庫主負責人,并做相應記錄。
在這些環境中,一定要做到權限劃分明確,讀寫帳號分離,并且有辨識度,能區分具體業務。例如用戶名w_wap、r_wap分別表示對wap數據庫進行讀、寫的帳號。
做企業內部應用系統,要求不是特別嚴格的話,沒有模擬環境和線上從庫。而且通常情況下,線上環境的庫在客戶那邊,開發測試的環境在公司這邊,兩邊還不能互通,有時不得不駐場開發直接連接線上環境。但是對于線上環境的直接操作是非常危險的,且容易導致線上環境和開發測試環境表結構的不同步,這個一定注意。客戶那邊應該用權限嚴格限制對生產環境訪問的人員,開發人員自己這邊要時刻做好數據備份工作,并提前準備好數據出現意外更改或丟失情況的應對措施。同時,在現場開發,針對線上環境的更改要實施同步到公司的開發環境中。線上線下的所有更改,都要經過數據庫主設計師的審核同意。
我們建議,如果可以控制的話,則在不同的數據庫環境中統一表空間名、數據庫名等,甚至是數據庫訪問的賬號名、權限也可以統一,這樣在部署項目時,配置文件則無需再做過多更改,不同數據庫環境間有表結構或數據的移植時也可避免出現不必要的問題。在對這些環境的數據庫進行備份時,建議在備份文件名中加上前綴和備份時間,以防混淆,比如備份開發環境的數據庫可命名為:DevelopmentEnvironment201703271149。這些都是非常細節的地方,有點吹毛求疵,不做強制要求。
B.數據庫功能塊概述
在前面“設計規范”——“基本原則”——“高級功能”中提到過,現有的開發模式,數據庫只用來做數據存儲。一直堅持業務相關的部分都由程序處理,不到不得以的情況下不要在數據庫中建存儲過程、觸發器、函數、序列甚至是視圖等,盡管如此,這里還是會簡單介紹下這些高級功能使用時的命名方式。下面的表格列出了數據庫所涵蓋常見功能元素的英文名稱及縮寫:
有建議,除表和表字段外,其它功能塊在命名時均要加英文縮寫前綴。但就個人意見,除視圖外,其它部分加不加前綴不太重要,視圖加前綴是為了在執行查詢時和表區分開,而存儲過程、函數、約束等,我們一眼即可看出它是什么,更何況在可視化管理工具中,這些功能塊本來就是各自獨立展示的。所以本規范中不強制要求在這些功能上加前綴,但如果要統一加的話,建議使用上圖表格中的英文縮寫。
C.關于數據表的命名
關于表的命名,TB這種前綴是毫無意義的,本來就是一個表,為什么還要說明?這也是我上面不建議在其它功能塊中加前綴的原因。如果表格數量較少,后期項目擴展升級的可能性不大,也沒有必要加其它前綴。但有時規模相對龐大、業務邏輯相對復雜的項目,表格數量多到一定程度,在可視化管理工具中查閱瀏覽不太方便,這時,根據業務或功能對表格進行分類,加前綴也就有必要了。個人感覺是50張表內的數據庫,加前綴意義不大,超過100張,則很有必要加前綴。而且我們要求,為了不給后期代碼生成造成非必要麻煩,如果要給表加前綴,則所有表均要有前綴,不要出現有些表有、有些沒有的情況。
表前綴主要是為了區分不同功能的表,而非解釋表的功能,表的功能由表名來解釋。前面要求表名的長度要控制在30個字符以內,在此前提下,為了盡可能不影響表的命名,表前綴應該越短越好。我們建議表前綴控制在兩個以內。具體表前綴添加規則建議如下,括號內的單個大寫字母表示要添加的前綴。這里以Oracle數據庫為例,具體表名、前綴的大小寫根據實際數據庫參照“命名規范”——“名大小寫”章節的說明:
a.系統表(S_):System,系統配置相關的基本信息表。系統用戶表(S_USER)、系統角色表(S_ROLE)、系統菜單(S_LINK_MENU)、操作日志(S_OPERATION_LOG)、登錄日志(S_LOGIN_LOG)、系統字典(S_DICTIONARY)、系統字典類型(S_DICTIONARY_TYPE)等。
b.字典表(D_):Dictionary,非系統字典外的字典表。在“設計規范”——“相關注釋”——“字典字段”中提到過字典表的定義,除了數據庫中的通用字典表,還有一些常見表,比如地區表(D_REGION)、ICD編碼(D_ICD)等,也是一種字典表,這里的D_前綴即加在這類字典表名前面。
c.中間表(R_):Relationship,多對多關系中間表。具體命名方式建議為:R_主表名_從表名,在多對多關系中其實不分主從表,這里我們規定核心表為主表,另外一個為從表。比如用戶角色關系中,用戶表(S_USER)為主、角色(S_ROLE)表為從,那中間表就命名為R_USER_ROLE。當中間表名超長時,則根據實際情況縮寫主從表名,建議優先縮寫從表表名。
d.業務表(B_):Business,核心業務涉及的基本信息表。這里的業務是非系統配置業務相關的,比如登錄、注冊、權限這些業務涉及的表都是和系統配置相關的,前綴應該是S_,而非B_。比如在線商城的項目中訂單業務涉及的表即是核心業務表,會診系統中會診單業務涉及的表即是核心業務表,如果項目龐大,涉及業務較多,可以在B后面繼續加單字母區分不同的業務,BA_、BB_、BC_……,沒必要非得和某個英文對應,只是個代號,和項目組的人員說明即可。
表名前綴的說明如上,已經足夠明確,除此外還應該避免無謂的表格后綴。比如存儲客戶信息的表直接命名為Guest而非GuestInfo,存儲航班信息的表直接命名為Flight而非FlightList。還有命名表時,一律使用單數形式。例如,使用Employee,而不是Employees,總之,表的命名應該簡單明了。
D.關于表字段的命名
a.所有表中的主鍵統一命名為id,主鍵統一使用UUID,類型統一為char(32)。不建議使用復合主鍵,即便是在多對多關系的中間表中,個人還是建議用單獨的字段做主鍵,復合字段加惟一約束。
b.所有的表字段中,除外鍵,其它字段名都無需刻意加前后綴,也不要在字段名前出現表名。這里的外鍵是廣義上的外鍵,不僅包括從表引用主表主鍵的外鍵字段,還包括存放主表相應關鍵信息的擴展字段。
比如病人表(Patient),主鍵就是id而不是pateint_id,名稱就是name而不是patient_name。但對于外鍵,比如其它表引用Patient表的主鍵那就是patient_id,對應Patient表的name字段那就是patient_name。如果一個表中有多個外鍵(字段)同時引用(對應)一張表的同一個字段,那再用其它標識,比如在“設計規范”——“基本原則”——“主鍵外鍵”中提到的會診單申請表中會診發起醫院(sender_hopital_id)和會診接收醫院(receiver_hospital_id)。
在前面的“設計規范”——“基本原則”——“主鍵外鍵”和“設計規范”——“約束控制”中有提到主鍵字段和外鍵字段的命名,這里再次做以上說明。另,PD中在由CDM轉換成PDM時,會自動根據引用關系在從表中添加外鍵字段,可以自定義外鍵名稱的命名規則:
c.在前面的“設計規范”——“基本原則”——“連接查詢”和“設計規范”——“相關注釋”——“字典字段”有關于字典字段的詳細介紹,這里再次說明其命名方式:對于字典字段,編碼字段后面跟Code后綴,文本字段跟Text后綴,比如gender_code、gender_text。
d.本規范中要求所有表示日期時間的字段,都要有后綴,如果只精確到天則以Date為后綴,如果要精確到時分秒那就用Time作后綴。在“設計規范”——“字段設置”——“通用字段處理”中有關于日期時間類型設置的說明,要求日期時間類型的字段,盡可能精確到時分秒,即便是像生日(birth_date)這種字段,一般只存儲到年月日,但在選擇字段類型時建議還是為datetime而非date。所以這里的后綴并不是和具體字段類型對應,而是根據實際業務情況,這個字段存儲的數據多是精確到年月日還是時分秒,則后綴相應的為Date或Time。
網上有建議說,日期時間不要用Time做后綴,因為Time還有一個很常用的意思,就是次數。比如登錄日志表中有用戶最后一次登錄時間字段login_time,不去看表的內容,很容易將login_time理解成登錄的次數。這里我們不予考慮,只要內部統一規范,這就不會是個問題。
e.本規范中建議是否注銷、是否成功等類似的布爾型字段,名稱前統一加is前綴,比如是否成功(is_success)、是否注銷(is_active)、是否顯示(is_display)等。
f.關于一些通用字段的命名方式建議如下,僅作參考:
E.關于約束控制命名
在“設計規范”——“約束控制”中介紹過五種約束類型:唯一性和主鍵約束、外鍵約束、檢查約束、空值約束、默認值約束,本規范中僅對外鍵約束的命名做要求,因外鍵約束標明著表與表之間的關系。我們建議外鍵約束以fk做前綴,后跟從表名稱和主表名稱:fk_從表名主表名。這種定義方式,約束名稱很容易超長,比如在Oracle中,約束名稱的長度限制和表名一樣,不能超過30個字符。如果超長,我們建議從后向前自動截取多出部分。前面提到過,CDM轉換成PDM時會自動根據引用關系在從表中添加外鍵字段,外鍵名稱的命名規則可以自定義。外鍵約束名稱沒必要手動添加,在PD的PDM圖中選擇:Database——Edit current DBMS——General選項卡——右側樹形菜單Script\Objects\Reference\ConstName,在里面可以編輯ConstraintName的命名方式,交由PD自動統一處理,比如可設置為:FK%.U30:CHILD%_%.U30:PARENT%。此設置在PD 15中起作用,16版本中的設置沒找到。
其它四種約束的命名,本規范中不做要求,竊以為這些約束怎樣命名也不太重要,如果需要統一命名規范,有些也可借助PD工具進行統一設置。
F.其它功能塊的命名
前面說過,因為自己所主張的開發模式,以往的項目中很少在數據庫中建存儲過程、觸發器、函數、序列、事件甚至是視圖等,這里只根據經驗,給出少量建議。
視圖的命名和表的命名有很多相似點,但認為視圖的名稱最好可直接反應出其查詢的主表,或者可明確反應出視圖功能。存儲過程、觸發器、函數、索引的名稱則直接反應其功能為好,其命名方式類似于在編程語言中給某一方法命名。序列只在Oracle中有,一般用來填充主鍵和計數。在早期的數據庫設計中,喜歡用自增主鍵,比如要讓用戶表(USER)的主鍵ID自增,則創建名為SQ_USER_ID的序列和名為TR_SET_USER_ID的觸發器。序列名直接反應出自己要計數的表的列,觸發器名直接反應出自己的功能,這種命名方式或可借鑒。
不過后期項目的數據庫設計,自己不再用自增主鍵,原因在“設計原則”——“基本規范”——“主鍵外鍵”中有描述。如果項目龐大,數據庫設計的模式有變動,要大量使用存儲過程、觸發器、函數、序列等,對于這些部分的命名還是有必要規范化的。
5、梳理總結
牽涉的細節太多,在介紹過程中也一直妄求事無巨細,反而導致有些地方比較散亂,這里把關鍵部分梳理總結如下:
a.建議在SQLServer中將排序規則設置為Chinese_PRC_CS_AS,在MySQL數據庫中將Character Set設置為utf8、將Collation設置為utf8_bin,并在數據庫配置文件中設置lower_case_table_names=1,
b.數據庫、表、字段等所有名稱的可用字符范圍為:A-Z,a-z,0-9和_下劃線,長度要嚴格控制在30個字符以內。
c.數據庫、表、字段等所有名稱均使用英文單詞或英文短語或相應縮寫,均使用單數名,禁止使用漢語拼音。
d.Oracle表、字段等名稱的統一使用大寫,單詞間用下劃線分隔;SQLServer數據庫、表等名稱采用Pascal命名法,字段名稱采用Camel命名法;MySQL數據庫、表、字段等名稱統一使用小寫,單詞間用下劃線分隔。
e.表主鍵統一命名為id,主鍵統一使用UUID,類型統一為char(32)。
f.表(廣義)外鍵建議命名為:主表名_字段名,類型和主表中字段類型一樣。如果一個表中有多個外鍵(字段)同時引用(對應)一張表的同一個字段,再根據實際情況加前后綴區分
g.對于字典字段,編碼字段后面跟Code后綴,文本字段跟Text后綴,
h.表示日期時間的字段,都要有后綴,如果只精確到天則以Date為后綴,如果要精確到時分秒那就用Time作后綴。
i.建議是否注銷、是否成功等類似的布爾型字段,名稱前統一加is前綴,比如是否成功(is_success)、是否注銷(is_active)、是否顯示(is_display)等。
j. 建議外鍵約束以fk做前綴,后跟從表名稱和主表名稱:fk_從表名_主表名。
參考:
數據庫設計中的命名規范