1.1數據庫對象
| 對象 |
前綴 |
| 數據庫 |
無 |
| 表 |
無 |
| 視圖 |
VI |
| 索引 |
IX |
| 存儲過程 |
SP |
| 函數 |
FN |
| 觸發器 |
TR |
| 自定義數據類型 |
ud |
| Default |
DF |
| 主鍵 |
pct. |
| 外鍵 |
FK |
| rule |
ru |
| 序列 |
Sq |
| UNIQUE |
uq |
數據庫對象采用26個英文字母(區分大小寫)和0-9這十個自然數,加上下划線_組成,共63個字符。不能出現其他字符(注釋除外)。
同一個數據庫中這些對象名都是不能重復
C CHECK_CONSTRAINT
D DEFAULT_CONSTRAINT
F FOREIGN_KEY_CONSTRAINT
IT INTERNAL_TABLE
P SQL_STORED_PROCEDURE
PK PRIMARY_KEY_CONSTRAINT
S SYSTEM_TABLE
SQ SERVICE_QUEUE
TR SQL_TRIGGER
U USER_TABLE
UQ UNIQUE_CONSTRAINT
V VIEW
1.2命名規范規定
1.表名使用單數名
例如:對用戶信息的表(User)不使用Users
2.避免無謂的表格后綴
1、 表是用來存儲數據信息的,表是行的集合。那么如果表名已經能夠很好地說明其包含的數據信息,就不需要再添加體現上面兩點的后綴了。
2、 GuestInfo(存儲客戶信息)應寫成Guest,FlightList(存儲航班信息的表)應寫成Flight
3.所有表示時間的字段,統一以 Date 來作為結尾(而不是有的使用Date,有的使用Time)
以大家都熟悉的論壇來說,需要記錄會員最后一次登錄的時間,這時候一般人都會把這個字段命名為LoginTime 或者 LoginDate。這時候,已經產生了一個歧義;如果僅看表的字段名稱,不去看表的內容,很容易將LoginTime理解成登錄的次數,因為,Time還有一個很常用的意思,就是次數
4.所有表示數目的字段,都應該以Count作為結尾
5.所有代表鏈接的字段,均為Url結尾
6.所有名稱的字符范圍為:A-Z, a-z, 0-9 和_(下划線)。不允許使用其他字符作為名稱。
7.采用英文單詞或英文短語(包括縮寫)作為名稱,不能使用無意義的字符或漢語拼音。
8.名稱應該清晰明了,能夠准確表達事物的含義,最好可讀,遵循“見名知意”的原則。
為避免無法達到“見名知意”的效果,表和字段的都需要添加備注(MS_Description)
9.為避免關鍵詞沖突,所有字段使用f開頭。例如 用戶Id(fUserId)
1.3數據庫命名規范
數據庫名稱不需要簡寫,根據實際意義來命名。例如:ReportServer
數據庫名:ReportServer
邏輯數據名:ReportServer;邏輯日志名:ReportServer_log
物理數據名:ReportServer.mdf;物理日志名:ReportServer_log.LDF
CREATE DATABASE [ReportServer] ON PRIMARY
( NAME = N'ReportServer', FILENAME = N'D:\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\useData\ReportServer.mdf' , SIZE = 3328KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'ReportServer_log', FILENAME = N'D:\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\useData\ReportServer_log.LDF' , SIZE = 6400KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
注意:避免所有數據庫的邏輯名稱使用相同的名稱。
1.4表設計命名規范
注意字段名不能使用保留關鍵字:如action,avg等
1、不使用tab或tbl作為表前綴(本來就是一個表,為什么還要說明)
2、表名以代表表內的內容的一個和多個名詞組成,以下划線分隔,每個名詞的第一個字母大寫,例如:User、UserLogin,UserGroupRelation等
3、使用表的內容分類作為表名的前綴:如,與用戶信息相關的表使用前綴User,與內容相關的信息使用前綴Content。
4、表的前綴以后,是表的具體內容的描述。如:用戶登錄信息的表名為:UserLogin,用戶在論壇中的信息的表名為:UserBBSInfo
5、一些作為多對多連接的表,可以使用兩個表的前綴作為表名:
如:用戶登錄表UserLogin,用戶分組表GroupInfo,這兩個表建立多對多關系的表名為:UserGroupRelation
1.4.1字段命名規范
1. 字段名不要存在無用前綴,例如表‘WeiXinConfig’,既然我已經知道這張表是關於微信的表,里面的名稱字段可以使用Name,不需要添加無用的前綴類似‘WeiXinName’,‘WeiXinGuanZhuMsg’,‘WeiXinUpImgMsg’等
2. 字段使用實際英文翻譯作為命名字段,見名知意,不要使用讓人看了半天都不知道是啥意思的字段(類似:lev1,lev2…)
1.5存儲過程命名
存儲過程名=[SP_]+[表名]+[操作名字]
[操作名字]=[insert|delete|update|calculate|confirm]
例如:SP_community_update
1.5.1只允許應用程序通過存儲過程訪問數據庫
只允許應用程序通過存儲過程訪問數據庫,而不允許直接在代碼中寫SQL語句訪問數據庫。
在數據庫開發項目中,大量使用存儲過程有很多的好處,首先看微軟提供信息:
| 使用 SQL Server 中的存儲過程而不使用存儲在客戶計算機本地的 Transact-SQL 程序的優勢有: 允許模塊化程序設計: 只需創建過程一次並將其存儲在數據庫中,以后即可在程序中調用該過程任意次。存儲過程可由在數據庫編程方面有專長的人員創建,並可獨立於程序源代碼而單獨修改。 允許更快執行: 如果某操作需要大量 Transact-SQL 代碼或需重復執行,存儲過程將比 Transact-SQL 批代碼的執行要快。將在創建存儲過程時對其進行分析和優化,並可在首次執行該過程后使用該過程的內存中版本。每次運行 Transact-SQL 語句時,都要從客戶端重復發送,並且在 SQL Server 每次執行這些語句時,都要對其進行編譯和優化。 減少網絡流量: 一個需要數百行 Transact-SQL 代碼的操作由一條執行過程代碼的單獨語句就可實現,而不需要在網絡中發送數百行代碼。 可作為安全機制使用: 即使對於沒有直接執行存儲過程中語句的權限的用戶,也可授予他們執行該存儲過程的權限。
|
除此以外,使用存儲過程的好處還有:
1、 在邏輯上,存儲過程將應用程序層和數據庫物理結構分離開來。存儲過程形成了一個應用程序和數據庫之間的接口。這樣的接口抽象了復雜的數據庫結構,符合極限編程中“基於接口編程”的思想。
2、 將主要的業務邏輯封裝在存儲過程中,能夠避免在應用程序層寫大量的代碼(在應用程序中通過字符串插入太長的SQL語句影響效率,而且維護困難)。有助於提高開發效率,並且直接在查詢分析器中調試存儲過程,能夠更早的發現系統中的邏輯問題,從而提高代碼的質量。
3、 在網站一類的應用系統中,SQL注入式漏洞一直是難以完全杜絕的漏洞。如果只通過存儲過程來訪問數據庫,能夠大大減少這類安全性問題。(因此,就算是簡單的只有一句的SQL語句,也應該寫成存儲過程。)
4、 由於采用存儲過程,應用程序的層面可以不關心具體的數據庫結構,而只關心存儲過程的接口調用。因此,在以下一些情況,存儲過程的優勢非常明顯:
·需求變更,表的結構必須要改變。使用存儲過程,只要參數不變,我們就只需要修改相應的存儲過程,而不需要修改應用程序的代碼。這樣的設計將減小需求變更對項目的影響。
·為提高效率,使部分字段冗余:一些經常性訪問的字段,我們可以在相關的表中進行冗余存儲。這樣既提高了效率,又通過存儲過程屏蔽了冗余細節。
·為提高效率,使用冗余表(拆分表):一些大的表,為了提高查詢效率,可能需要將記錄分別保存到多個表中去。使用存儲過程,有存儲過程來決定從哪些拆分的表中獲取或插入數據。這樣提高了效率,又不必在應用程序層面關心具體的拆分規則。
5、 使用存儲過程,便於在項目后期或者運行中集中優化系統性能。在項目開發過程中,由於各種原因,往往無法編寫高效的代碼,這個問題常常在項目后期或者在運行期體現出來。通過存儲過程來封裝對數據庫的訪問,可以在項目集成以后,通過試運行觀察系統的運行效率,從而很容易找出系統的瓶頸,並能夠通過優化存儲過程的代碼來提高系統的運行效率。這樣的優化,比在運用程序中優化更有效,更容易。
同時,過多的使用存儲過程,也存在以下一些疑慮:
問題一:存儲過程編譯后,將作為數據庫的全局對象保存,太多的存儲過程將占用大量的數據庫服務器的內存。
問題二:在存儲過程中實現大量的邏輯,將使大量的運算在數據庫服務器上完成,而不是在應用服務器上完成。當訪問量很大的時候,會大大消耗數據庫服務器的CPU占用率。
在此還存在這個一個案例:有一個訪問量巨大的網站,有多台WEB服務器構成一個負載均衡的服務器群集,但是只有一台中心的數據庫服務器。當訪問量持續增加的時候,接入更多的WEB服務器來滿足高並發量的訪問;但是數據庫服務器卻沒辦法一直增加。因此,就需要盡量在WEB服務器上完成業務邏輯,盡量避免消耗數據庫服務器的資源。
對於這兩個擔心,我的想法是:
問題一的解決:存儲過程是經過編譯后的SQL語句,在內存中是二進制的代碼,並不會消耗太多內存。並且,存儲過程比起直接使用SQL語句來說,效率大大提高。換個角度來說,這是一個“以空間換時間”的方案,多消耗一點內存來換取效率的提高,是值得的。
問題二的解決:首先,在實現業務邏輯的問題上,在存儲過程中實現比在應用程序中實現更容易;其次,從開發效率上,存儲過程的開發比應用程序更簡單(就完成相同邏輯而言)。在高訪問量的系統中,應用服務器和數據庫服務器的資源分配的問題,應該從成本的角度來開率:軟件開發中的成本,人工支出的費用遠遠高於硬件支出的成本。我們可以很容易花錢購買更好的服務器,但是很難花錢讓開發人員使程序有大幅度的提高。
使用存儲過程來封裝業務邏輯,首先節省的是大量的開發時間和調試時間,並能夠大大提高代碼的質量。因此,從成本來說,應該使用存儲過程。
對於大訪問量的情況,最簡單的辦法是投入更多的硬件成本:更快的硬盤,更大的內存和更多的CPU,還有更好的網卡…………等等。
其次,在應用程序的層面,可以大量的使用靜態文件緩存的辦法來減輕數據庫的壓力。如:不經常變化的信息,可以從數據庫服務器中讀取,保存為應用服務器上的XML靜態文件等。
實在不行的話,應該在系統設計之初,考慮可能的訪問量,將系統設計成分布式的。這樣就能從根本上解決大訪問量的問題。
1.5.2命名規范
1、存儲過程的前綴和表名的前綴類似:把一系列表看成一個對象,字段為對象的屬性,存儲過程則為訪問對象的方法。如:添加用戶的存儲過程取名為:User_AddUser
2、存儲過程使用模塊的前綴來命名。如,用戶管理的存儲過程使用前綴user_。
3、存儲過程的前綴之后,是動詞+名詞形式的存儲過程名(也可以是動詞短語)。
1.5.3存儲過程的參數命名
1、參數名采用匈牙利命名法,使用類型的前綴
2、每個存儲過程都有:@errno int和@errmsg varchar(255)兩個輸出參數。應用程序中可以根據這兩個參數得到存儲過程執行的情況。(這兩個參數使用默認值,可以忽略)
errno為整型的錯誤信息代碼,執行成功返回0。Errno的值的具體含義通過errmsg參數說明,或者通過代碼中的注釋或文檔。
Errmsg為錯誤信息的字符串描述,這個參數主要用於調試期作為說明,避免在應用程序中使用該值。同時,要注意英文版系統和中文版系統中,信息的語言選擇對程序的影響。
1.5.4存儲過程返回的記錄集
1、存儲過程的輸出記錄集:為程序的結構清晰,存儲過程最好只返回一個記錄集。但在某些為了提高性能的場合,還是可以輸出多個記錄集
2、記錄集中,每個輸出的字段最后都指定字段的別名,以面真實的字段名信息流失到客戶端,從而加大黑客找到系統漏洞的可能。
1.5.5格式約定
1、 所有SQL關鍵字大寫
2、 使用良好的變量命名規范
3、 保持良好的結構,包括空行、縮進和空格等。
4、 塊狀的語句,一定要寫上BEGIN…END
5、 在每個存儲過程的開頭加上詳細的注釋:包括存儲過程名稱、參數說明、功能說明、返回數據集說明、以及作者和版權聲明。
6、 每個存儲過程內的代碼前后必須加上SET NOCOUNT ON 和SET NOCOUNT OFF。
7、 存儲過程格式的示例如下:
CREATE PROCEDURE SP_User_update
(
@Options VarChar(100),
@strUserName varchar(20),
@strPwd varchar(50),
@errno int = 0 OUTPUT,
@errmsg varchar(255)=NULL OUTPUT
)
AS
BEGIN
IF @Options='UP1'
BEGIN
SET NOCOUNT ON
/*以下是存儲過程的代碼*/
SET NOCOUNT OFF
END
IF @Options='UP2'
BEGIN
SET NOCOUNT ON
/*以下是存儲過程的代碼*/
SET NOCOUNT OFF
END
END
1.6視圖命名
一個數據庫中的視圖名不能重復
視圖名=VI(前綴)+[表名]..[表名]+[描述]
1.7主鍵命名
一個數據庫中的主鍵名不能重復
主鍵名=PK_(前綴)+[表名]
例如:PK_Community
1.8外鍵命名
一個數據庫中的外鍵名不能重復
外鍵名=FK_(前綴)+[主表名]+[從表名]+[字段名]
考慮這樣一個關系,表Hotel,字段fId, fName, fCityId。表fCity,字段fId,fName。因為一個城市可能有好多家酒店,所以是一個一對多的關系,fCity是主表(1方),fHotel是從表(多方)。在fHotel表中,fCityId是做為外鍵使用。
在實現外鍵的時候我們可以這樣寫:
ALTER TABLE HotelInfo
ADD CONSTRAINT FK_Hotel_City_Cityid FOREIGN KEY (CityID) REFERENCES City(ID)
1.9觸發器命名
1. 前綴(tr),描述了數據庫對象的類型。
2. 基本部分,描述觸發器所加的表。
3. 后綴(_I、_U、_D),顯示了修改語句(Insert, Update及Delete)
觸發器名=TR_(前綴)+[表名]+[ _I、_U、_D]+[字段\描述]
例如:TR _Communtiy_u_name(對表community的字段name進行更新)
1.10 default約束
使用格式如:DF_[表名]_[列名]
例如:DF _Community_Age
1.11 check約束
格式:CK_[表名]_[列名]
例如:CK_Community_Number
1.12 unique約束
格式:UQ_[表名]_[列名]
例如:UQ_Community_Name
1.13字段命名規范
1、字段不使用任何前綴(表名代表了一個名稱空間,字段前面再加前綴顯得羅嗦)
2、字典名也避免采用過於普遍過於簡單的名稱:例如,用戶表中,用戶名的字段為UserName比Name更好。
3、布爾型的字段,以一些助動詞開頭,更加直接生動:如,用戶是否有留言HasMessage,用戶是否通過檢查IsChecked等。
4、字段名為英文短語、形容詞+名詞或助動詞+動詞時態的形式表示,大小寫混合,遵循“見名知意”的原則。
1.14 SQL語句規范
1、不允許寫SELECT * FROM ……,必須指明需要讀取的具體字段。
2、不允許在應用程序代碼中直接寫SQL語句訪問數據庫。
3、避免在一行內寫太長的SQL語句,在SQL關鍵字的地方將SQL語句分成多行會更加清晰。
如:SELECT fUserID,fUserName,fUserPwd FROM User_Login WHERE fAreaID=20
修改成:
SELECT fUserID,fUserName,fUserPwd
FROM User_Login
WHERE fAreaID=20
更加直觀
4、在一些塊形式的SQL語句中,就算只有一行代碼,也要加上BEGIN…END塊。
如:IF EXISTS(…)
SET @nVar = 100
應該寫成:
IF EXISTS(…)
BEGIN
SET @nVar = 100
END
5、SQL批處理語句的空行和縮進與一般的結構化程序語言一致,應該保持良好的代碼格式。
6、所有的SQL關鍵字大寫
1.15游標使用約定
1、 若無必要,不要使用游標
2、 包含游標的存儲過程,必須對性能進行認真測試。
1.16索引命名規范
對於數據庫的維護建索引是很平常的事情,但是如果沒有一個規范化的命名,我們對於一個表的諸多索引可能需要花上一段時間的了解。
1. 如果表中存在主鍵默認情況下,表的聚集性索引也就是主鍵列,主鍵的命名前面已經有提到過,索引名也跟主鍵名一樣,(PK_表名)
2. 對於表上的非聚集索引,建議使用(IX_表名_字段簡寫),對於很多命名文章上提到的需要詳細表達出具體的列,我個人覺得沒有必要,首先非聚集索引經常涉及多列,很難羅列出所有列;還有影響美觀
當你執行SELECT fNAME FROM SYS.COLUMNS 查詢索引時,你根據NAME名很快就知道索引來自那張表,是否是非聚集索引,而不用根據OBJECTID列去跟對象表關聯。
1.17函數命名規范
函數命名分兩類:1.針對對象的函數,2.用作輔助功能操作的函數(不針對具體的數據庫對象)
1. 第一類命名:FN_+[User]+_+[對象名] 例如:FN_User_Student(對於Student進行操作函數)
2. 第二類命名:FN_[具體函數解釋] 例如:FN_Spit(對字段進行拆分函數)
