數據庫設計是指對一個給定的應用環境,構造最優的數據庫模式,創建數據庫及其餘應用系統,使之能有效地存儲數據,知足各類用戶的需求。數據庫設計過程當中命名規範非常重要,命名規範合理的設計可以省去開發人員不少時間去區別數據庫實體。程序員
最近也由於工做須要因此整理出了這個word文檔,望你們指正。數據庫
數據庫規劃→需求分析→數據庫設計→應用程序設計→實現→測試→運行於維護編程
定義數據庫應用系統的主要目標,定義系統特定任務,包括工做量的估計、使用資源、和需求經費,定義系統的範圍以及邊界。緩存
涉及人員:用戶和分析人員安全
任務:對現實世界要處理的對象進行詳細的調查,收集基礎數據及處理方法,在用戶調查的基礎上經過分析,逐步明確用戶對系統的需求,包括信息的要求及處理的要求。服務器
方法與步驟:1.經過與用戶的調查,對用戶的信息需求進行收集。微信
2.在收集數據的同時,設計人員要對其進行加工和整理,以數據字典和數據流圖的形式描述出來,並以設計人員的角度向用戶講述信息,根據用戶的反饋加以修改並肯定(該過程是反覆的過程)網絡
成果:數據流圖,數據字典,各類說明性表格,統計輸出表以及系統功能結構圖。併發
外部實體:存在於軟件系統以外的人員或組織(正方形或立方體表示)。負載均衡
加工:數據處理,表示輸入數據在此進行變換,產生輸出數據(圓角巨型或圓形表示)。
數據流:表示流動着的數據(箭頭線表示)。
數據存儲:用來表示要存儲的數據(開門矩形或兩條平行橫線表示)。
訂單處理系統頂層流程圖:
0層數據流圖:
實體:現實中的事物例如,學生,老師
聯繫:兩個實體之間的關係,1:一、1:N、M:N三種關係
屬性:實體所具備的屬性,例如 學生的學號、姓名、性別等
例如:一個學生屬於一個班級,一個班級擁有多名學生,E-R圖以下
網上購物系統E-R圖,該系統數據之間存在下列約束
圖2.2
將每一個實體轉換成一個關係模式,實體的屬性即關係模式的屬性,實體的標識即關係模式的鍵。
根據E-R圖實體之間的聯繫能夠轉換成如下關係模式:
客戶(客戶編號,姓名,電話,E-mail)。關係的主鍵:客戶編號;外鍵:無
訂單(訂單編號,訂購時間,客戶編號)。關係的主鍵:訂單編號;外鍵:客戶編號
訂購細目(訂購明細編號,訂購數量,支付金額,訂單編號)。關係主鍵:訂購明細編號;外鍵:訂單編號。
出現(訂購明細編號,商品編號,類型)。關係的主鍵:訂購明細編號,商品編號;外鍵:訂購明細編號,商品編號。
商品:(商品編號,商品名稱,單價,生產日期,商品類別號,商品類別名)。關係的主鍵:商品編號;外鍵:無
在關係模式設計中可能會出現如下幾個問題:數據冗餘、數據修改不一致、數據插入異常、數據刪除異常,因此提出範式的要求,目的就是最低限度地冗餘,避免插入、刪除、修改異常。
主屬性:包含鍵的全部屬性。
第一範式(1NF):若關係模式R的每個份量是不可分的數據項,則關係模式屬於第一範式。即每一個屬性都是不可拆分的.
第二範式(2NF):R屬於1NF,且每個非主屬性徹底依賴於鍵(沒有部分依賴),則R屬於2NF
例如:選課關係(學號,課程號,成績,學分)
該關係的主鍵是(學號,課程號),可是課程號→學分,因此學分屬性部分依賴於主鍵,即關係部知足第二範式,能夠拆分爲(學號,課程號,成績),(課程號,學分)兩個關係
第三範式(3NF):R屬於2NF,且每一個非主屬性即不部分依賴於碼,也不傳遞依賴於碼
例如:學生關係(學號,姓名,所屬系,系地址)
該關係的主鍵是:學號
學號→所屬系,所屬系→學號,所屬系→系地址;根據函數的依賴公理,系地址傳遞函數依賴於學號,即關係不知足第三範式,能夠拆分關係爲(學號,姓名,所屬系),(所屬系,系地址)
若是不拆分會存在數據修改異常,好比該學生的換了系,修改了所屬系,可是系地址沒有修改,這樣就形成了修改異常
BCNF:R屬於3NF,且不存在主屬性對碼的部分和傳遞函數依賴
例如:關係R(零件號,零件名,廠商名),若是設定每種零件號只有一個零件名,但不一樣的的零件號能夠有相同的零件名,每種零件能夠有多個廠商生產,但每家廠商生產的零件應有不一樣的零件名。這樣能夠獲得:
零件號→零件名,(廠商名,零件名)→零件號
因此主屬性包括(零件號,廠商名,零件名),可是「零件名」傳遞依賴於碼「廠商名,零件名」,因此關係R不知足BCNF,當一個零件由多個生產廠商生產時,因爲零件號只有一個而零件名根據廠商不一樣而又多個,零件名與零件號之間的聯繫將屢次重複,帶來數據冗餘和操做異常現象
能夠將關係分解爲(零件號,廠商名),(零件號,零件名)
4NF:關係模式R屬於1NF,若對於R的每一個非平凡多值依賴X→→Y且Y不包含於X時,X必含碼,則R屬於4NF
5NF:對關係進行投影,消除關係中不是由候選碼所蘊含的鏈接依賴
對於上面的商品關係,因爲關係的主鍵是商品編號,而商品類別號→商品類別名
因此商品關係部知足第三範式,非主屬性商品類別名傳遞依賴於商品編號,會存在數據冗餘,數據修改異常問題。將商品關係分解爲:
商品(商品編號,商品名稱,單價,生產日期,商品類別號)
商品類別(商品類別號,商品類別名)
爲一個給定的邏輯數據模型設計一個最合適應用要求的物理結構的過程
採用高級語言以結構化設計方法或面向對象方法進行設計
1.若是頻繁地訪問涉及的是對兩個相關的表進行鏈接操做,則考慮將其合併
2.若是頻繁地訪問只是在表中的某一部分字段上進行,則考慮分解表,將該部分單獨做爲一個表
3.對於不多更新的表,引入物化視圖
4. 當系統中有一些少許的,重複出現的值時,使用字典表來節約存儲空間和優化查詢。如地區、系統中用戶類型的代號等。這類值不會在程序的運行期變化,可是須要存儲在數據庫中。
就地區而言,若是咱們要查詢某個地區的記錄,則數據庫須要經過字符串匹配的方式來查詢;若是將地區改成一個地區的代號保存在表中,查詢時經過地區的代號來查詢,則查詢的效率將大大提升。
程序中宜大量的使用字典表來表示這類值。字典表中保存這類值的代號和實體的集合,之外鍵的方式關聯到使用這類值的表中。然而,在編碼階段,程序員並不使用字典表,由於首先查詢字典表中實體的代號,違背了提升查詢效率的初衷。程序員在數據字典的幫助下,直接使用代號來表明實體,從而提升效率。
雖然字典表在實際上並不使用,可是仍應該保留在數據庫中(起碼是在開發期內保留)。字典表做爲另外一種形式上的「數據字典文檔」出現,以說明數據庫中哪些表的哪些字段是使用了字典表的。
爲了提升數據庫的數據完整性,在開發階段能夠保留完整的字典表和普通表的外鍵約束。可是在數據庫的運行階段,應該將普通表和字典表的外鍵刪除,以提升運行效率,特別是某些表使用了不少字典表的狀況。
案例:某數據庫中有百萬條用戶信息,應用系統中經常須要按照地區要查詢用戶的信息。用戶信息表之前是按照具體的地區名稱來保存的,如今將具體的名稱改成字典表中的地區代號,查詢效率大大提升。
對象 |
前綴 |
數據庫 |
無 |
表 |
無 |
視圖 |
VW |
索引 |
IX |
存儲過程 |
SP\SPChange |
函數 |
FN |
觸發器 |
TR |
自定義數據類型 |
UD |
Default |
DF |
主鍵 |
PK |
外鍵 |
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.表名使用單數名
例如:對存儲客人信息的表(Customer)不使用Customers
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.名稱應該清晰明瞭,可以準確表達事物的含義,最好可讀,遵循「見名知意」的原則。
數據庫名稱不須要簡寫,根據實際意義來命名。例如: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
注意:避免全部數據庫的邏輯名稱使用相同的名稱。
注意字段名不能使用保留關鍵字:如action,avg等
一、不使用tab或tbl做爲表前綴(原本就是一個表,爲何還要說明)
二、表名以表明表內的內容的一個和多個名詞組成,如下劃線分隔,每一個名詞的第一個字母大寫,例如:User、UserLogin,UserGroupRelation等
三、使用表的內容分類做爲表名的前綴:如,與用戶信息相關的表使用前綴User,與內容相關的信息使用前綴Content。
四、表的前綴之後,是表的具體內容的描述。如:用戶登陸信息的表名爲:UserLogin,用戶在論壇中的信息的表名爲:UserBBSInfo
五、一些做爲多對多鏈接的表,可使用兩個表的前綴做爲表名:
如:用戶登陸表UserLogin,用戶分組表GroupInfo,這兩個表創建多對多關係的表名爲:UserGroupRelation
存儲過程名=[SP]+[查詢修改標示]+[表名]
例如:
查詢存儲過程
SPCommunity
修改存儲過程
SPChangeCommunity
只容許應用程序經過存儲過程訪問數據庫,而不容許直接在代碼中寫SQL語句訪問數據庫。
在數據庫開發項目中,大量使用存儲過程有不少的好處,首先看微軟提供信息:
使用 SQL Server 中的存儲過程而不使用存儲在客戶計算機本地的 Transact-SQL 程序的優點有: 容許模塊化程序設計: 只需建立過程一次並將其存儲在數據庫中,之後便可在程序中調用該過程任意次。存儲過程可由在數據庫編程方面有專長的人員建立,並可獨立於程序源代碼而單獨修改。 容許更快執行: 若是某操做須要大量 Transact-SQL 代碼或需重複執行,存儲過程將比 Transact-SQL 批代碼的執行要快。將在建立存儲過程時對其進行分析和優化,並可在首次執行該過程後使用該過程的內存中版本。每次運行 Transact-SQL 語句時,都要從客戶端重複發送,而且在 SQL Server 每次執行這些語句時,都要對其進行編譯和優化。 減小網絡流量: 一個須要數百行 Transact-SQL 代碼的操做由一條執行過程代碼的單獨語句就可實現,而不須要在網絡中發送數百行代碼。 可做爲安全機制使用: 即便對於沒有直接執行存儲過程當中語句的權限的用戶,也可授予他們執行該存儲過程的權限。
|
除此之外,使用存儲過程的好處還有:
一、 在邏輯上,存儲過程將應用程序層和數據庫物理結構分離開來。存儲過程造成了一個應用程序和數據庫之間的接口。這樣的接口抽象了複雜的數據庫結構,符合極限編程中「基於接口編程」的思想。
二、 將主要的業務邏輯封裝在存儲過程當中,可以避免在應用程序層寫大量的代碼(在應用程序中經過字符串插入太長的SQL語句影響效率,並且維護困難)。有助於提升開發效率,而且直接在查詢分析器中調試存儲過程,可以更早的發現系統中的邏輯問題,從而提升代碼的質量。
三、 在網站一類的應用系統中,SQL注入式漏洞一直是難以徹底杜絕的漏洞。若是隻經過存儲過程來訪問數據庫,可以大大減小這類安全性問題。(所以,就算是簡單的只有一句的SQL語句,也應該寫成存儲過程。)
四、 因爲採用存儲過程,應用程序的層面能夠不關心具體的數據庫結構,而只關心存儲過程的接口調用。所以,在如下一些狀況,存儲過程的優點很是明顯:
·需求變動,表的結構必需要改變。使用存儲過程,只要參數不變,咱們就只須要修改相應的存儲過程,而不須要修改應用程序的代碼。這樣的設計將減少需求變動對項目的影響。
·爲提升效率,使部分字段冗餘:一些常常性訪問的字段,咱們能夠在相關的表中進行冗餘存儲。這樣既提升了效率,又經過存儲過程屏蔽了冗餘細節。
·爲提升效率,使用冗餘表(拆分表):一些大的表,爲了提升查詢效率,可能須要將記錄分別保存到多個表中去。使用存儲過程,有存儲過程來決定從哪些拆分的表中獲取或插入數據。這樣提升了效率,又沒必要在應用程序層面關心具體的拆分規則。
五、 使用存儲過程,便於在項目後期或者運行中集中優化系統性能。在項目開發過程當中,因爲各類緣由,每每沒法編寫高效的代碼,這個問題經常在項目後期或者在運行期體現出來。經過存儲過程來封裝對數據庫的訪問,能夠在項目集成之後,經過試運行觀察系統的運行效率,從而很容易找出系統的瓶頸,並可以經過優化存儲過程的代碼來提升系統的運行效率。這樣的優化,比在運用程序中優化更有效,更容易。
同時,過多的使用存儲過程,也存在如下一些疑慮:
問題一:存儲過程編譯後,將做爲數據庫的全局對象保存,太多的存儲過程將佔用大量的數據庫服務器的內存。
問題二:在存儲過程當中實現大量的邏輯,將使大量的運算在數據庫服務器上完成,而不是在應用服務器上完成。當訪問量很大的時候,會大大消耗數據庫服務器的CPU佔用率。
在此還存在這個一個案例:有一個訪問量巨大的網站,有多臺WEB服務器構成一個負載均衡的服務器羣集,可是隻有一臺中心的數據庫服務器。當訪問量持續增長的時候,接入更多的WEB服務器來知足高併發量的訪問;可是數據庫服務器卻沒辦法一直增長。所以,就須要儘可能在WEB服務器上完成業務邏輯,儘可能避免消耗數據庫服務器的資源。
對於這兩個擔憂,個人想法是:
問題一的解決:存儲過程是通過編譯後的SQL語句,在內存中是二進制的代碼,並不會消耗太多內存。而且,存儲過程比起直接使用SQL語句來講,效率大大提升。換個角度來講,這是一個「以空間換時間」的方案,多消耗一點內存來換取效率的提升,是值得的。
問題二的解決:首先,在實現業務邏輯的問題上,在存儲過程當中實現比在應用程序中實現更容易;其次,從開發效率上,存儲過程的開發比應用程序更簡單(就完成相同邏輯而言)。在高訪問量的系統中,應用服務器和數據庫服務器的資源分配的問題,應該從成本的角度來開率:軟件開發中的成本,人工支出的費用遠遠高於硬件支出的成本。咱們能夠很容易花錢購買更好的服務器,可是很難花錢讓開發人員使程序有大幅度的提升。
使用存儲過程來封裝業務邏輯,首先節省的是大量的開發時間和調試時間,並可以大大提升代碼的質量。所以,從成原本說,應該使用存儲過程。
對於大訪問量的狀況,最簡單的辦法是投入更多的硬件成本:更快的硬盤,更大的內存和更多的CPU,還有更好的網卡…………等等。
其次,在應用程序的層面,能夠大量的使用靜態文件緩存的辦法來減輕數據庫的壓力。如:不常常變化的信息,能夠從數據庫服務器中讀取,保存爲應用服務器上的XML靜態文件等。
實在不行的話,應該在系統設計之初,考慮可能的訪問量,將系統設計成分佈式的。這樣就能從根本上解決大訪問量的問題。
一、存儲過程的前綴和表名的前綴相似:把一系列表當作一個對象,字段爲對象的屬性,存儲過程則爲訪問對象的方法。如:添加用戶的存儲過程取名爲:User_AddUser
二、存儲過程使用模塊的前綴來命名。如,用戶管理的存儲過程使用前綴user_。
三、存儲過程的前綴以後,是動詞+名詞形式的存儲過程名(也能夠是動詞短語)。
一、參數名採用匈牙利命名法,使用類型的前綴
二、每一個存儲過程都有:@errno int和@errmsg varchar(255)兩個輸出參數。應用程序中能夠根據這兩個參數獲得存儲過程執行的狀況。(這兩個參數使用默認值,能夠忽略)
errno爲整型的錯誤信息代碼,執行成功返回0。Errno的值的具體含義經過errmsg參數說明,或者經過代碼中的註釋或文檔。
Errmsg爲錯誤信息的字符串描述,這個參數主要用於調試期做爲說明,避免在應用程序中使用該值。同時,要注意英文版系統和中文版系統中,信息的語言選擇對程序的影響。
一、存儲過程的輸出記錄集:爲程序的結構清晰,存儲過程最好只返回一個記錄集。但在某些爲了提升性能的場合,仍是能夠輸出多個記錄集
二、記錄集中,每一個輸出的字段最後都指定字段的別名,以面真實的字段名信息流失到客戶端,從而加大黑客找到系統漏洞的可能。
一、 全部SQL關鍵字大寫
二、 使用良好的變量命名規範
三、 保持良好的結構,包括空行、縮進和空格等。
四、 塊狀的語句,必定要寫上BEGIN…END
五、 在每一個存儲過程的開頭加上詳細的註釋:包括存儲過程名稱、參數說明、功能說明、返回數據集說明、以及做者和版權聲明。
六、 每一個存儲過程內的代碼先後必須加上SET NOCOUNT ON 和SET NOCOUNT OFF。
七、 存儲過程格式的示例以下:
CREATE PROCEDURE Pro_Alter_User
(
@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
一個數據庫中的視圖名不能重複
視圖名=VW(前綴)+[表名]..[表名]+[描述]
一個數據庫中的主鍵名不能重複
主鍵名=PK_(前綴)+[表名]
例如:PK_Community
一個數據庫中的外鍵名不能重複
外鍵名=FK_(前綴)+[主表名]+[從表名]+[字段名]
考慮這樣一個關係,表Hotel,字段Id, Name, CityId。表City,字段Id,Name。由於一個城市可能有好多家酒店,因此是一個一對多的關係,City是主表(1方),Hotel是從表(多方)。在Hotel表中,CityId是作爲外鍵使用。
在實現外鍵的時候咱們能夠這樣寫:
ALTER TABLE HotelInfo
ADD CONSTRAINT FK_Hotel_City_Cityid FOREIGN KEY (CityID) REFERENCES City(ID)
觸發器名=TR_(前綴)+[表名]+[ _I、_U、_D]+[字段\描述]
例如:TR _Communtiy_u_name(對錶community的字段name進行更新)
使用格式如:DF_[表名]_[列名]
例如:DF _Community_Age
格式:CK_[表名]_[列名]
例如:CK_Community_Number
格式:UQ_[表名]_[列名]
例如:UQ_Community_Name
一、字段不使用任何前綴(表名錶明瞭一個名稱空間,字段前面再加前綴顯得羅嗦)
二、字典名也避免採用過於廣泛過於簡單的名稱:例如,用戶表中,用戶名的字段爲UserName比Name更好。
三、布爾型的字段,以一些助動詞開頭,更加直接生動:如,用戶是否有留言HasMessage,用戶是否經過檢查IsChecked等。
四、字段名爲英文短語、形容詞+名詞或助動詞+動詞時態的形式表示,大小寫混合,遵循「見名知意」的原則。
一、不容許寫SELECT * FROM ……,必須指明須要讀取的具體字段。
二、不容許在應用程序代碼中直接寫SQL語句訪問數據庫。
三、避免在一行內寫太長的SQL語句,在SQL關鍵字的地方將SQL語句分紅多行會更加清晰。
如:SELECT UserID,UserName,UserPwd FROM User_Login WHERE AreaID=20
修改爲:
SELECT UserID,UserName,UserPwd
FROM User_Login
WHERE AreaID=20
更加直觀
四、在一些塊形式的SQL語句中,就算只有一行代碼,也要加上BEGIN…END塊。
如:IF EXISTS(…)
SET @nVar = 100
應該寫成:
IF EXISTS(…)
BEGIN
SET @nVar = 100
END
五、SQL批處理語句的空行和縮進與通常的結構化程序語言一致,應該保持良好的代碼格式。
六、全部的SQL關鍵字大寫
一、 若無必要,不要使用遊標
二、 包含遊標的存儲過程,必須對性能進行認真測試。
對於數據庫的維護建索引是很日常的事情,可是若是沒有一個規範化的命名,咱們對於一個表的諸多索引可能須要花上一段時間的瞭解。
當你執行SELECT NAME FROM SYS.COLUMNS 查詢索引時,你根據NAME名很快就知道索引來自那張表,是不是非彙集索引,而不用根據OBJECTID列去跟對象表關聯。
函數命名分兩類:1.針對對象的函數,2.用做輔助功能操做的函數(不針對具體的數據庫對象)
備註: 做者:pursuer.chen 博客:http://www.cnblogs.com/chenmh 本站點全部隨筆都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接,不然保留追究責任的權利。 《歡迎交流討論》 |