数据库设计原则
設計數據庫是實現實際業務的重要一步,合理設計表結構,規劃表字段,建立合理關系為后期減少了開發,運營,維護成本。認真了解和學習設計知識是必要的,如下摘抄了部分經驗總結。
一,數據庫設計原則
1. 原始單據與實體之間的關系?
可以是一對一、一對多、多對多的關系。在一般情況下,它們是一對一的關系:即一張原始單據對應且只對應一個實體。?
在特殊情況下,它們可能是一對多或多對一的關系,即一張原始單證對應多個實體,或多張原始單證對應一個實體。?
這里的實體可以理解為基本表。明確這種對應關系后,對我們設計錄入界面大有好處。?
〖例1〗:一份員工履歷資料,在人力資源信息系統中,就對應三個基本表:員工基本情況表、社會關系表、工作簡歷表。?
? 這就是“一張原始單證對應多個實體”的典型例子。?
2. 主鍵與外鍵?
一般而言,一個實體不能既無主鍵又無外鍵。在E—R 圖中, 處于葉子部位的實體, 可以定義主鍵,也可以不定義主鍵?
(因為它無子孫), 但必須要有外鍵(因為它有父親)。?
主鍵與外鍵的設計,在全局數據庫的設計中,占有重要地位。當全局數據庫的設計完成以后,有個美國數據庫設計專?
家說:“鍵,到處都是鍵,除了鍵之外,什么也沒有”,這就是他的數據庫設計經驗之談,也反映了他對信息系統核?
心(數據模型)的高度抽象思想。因為:主鍵是實體的高度抽象,主鍵與外鍵的配對,表示實體之間的連接。?
3. 基本表的性質?
基本表與中間表、臨時表不同,因為它具有如下四個特性:?
(1) 原子性。基本表中的字段是不可再分解的。?
(2) 原始性。基本表中的記錄是原始數據(基礎數據)的記錄。?
(3) 演繹性。由基本表與代碼表中的數據,可以派生出所有的輸出數據。?
(4) 穩定性。基本表的結構是相對穩定的,表中的記錄是要長期保存的。?
理解基本表的性質后,在設計數據庫時,就能將基本表與中間表、臨時表區分開來。?
4. 范式標準?
基本表及其字段之間的關系, 應盡量滿足第三范式。但是,滿足第三范式的數據庫設計,往往不是最好的設計。?
為了提高數據庫的運行效率,常常需要降低范式標準:適當增加冗余,達到以空間換時間的目的。?
〖例2〗:有一張存放商品的基本表,如表1所示。“金額”這個字段的存在,表明該表的設計不滿足第三范式,?
因為“金額”可以由“單價”乘以“數量”得到,說明“金額”是冗余字段。但是,增加“金額”這個冗余字段,?
可以提高查詢統計的速度,這就是以空間換時間的作法。?
在Rose 2002中,規定列有兩種類型:數據列和計算列。“金額”這樣的列被稱為“計算列”,而“單價”和?
“數量”這樣的列被稱為“數據列”。?
表1 商品表的表結構?
商品名稱 商品型號 單價 數量 金額?
電視機 29吋 2,500 40 100,000?
?
5. 通俗地理解三個范式?
通俗地理解三個范式,對于數據庫設計大有好處。在數據庫設計中,為了更好地應用三個范式,就必須通俗地理解?
三個范式(通俗地理解是夠用的理解,并不是最科學最準確的理解):?
第一范式:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解;?
第二范式:2NF是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性;?
第三范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余。?
沒有冗余的數據庫設計可以做到。但是,沒有冗余的數據庫未必是最好的數據庫,有時為了提高運行效率,就必須降?
低范式標準,適當保留冗余數據。具體做法是:在概念數據模型設計時遵守第三范式,降低范式標準的工作放到物理?
數據模型設計時考慮。降低范式就是增加字段,允許冗余。?
6. 要善于識別與正確處理多對多的關系?
若兩個實體之間存在多對多的關系,則應消除這種關系。消除的辦法是,在兩者之間增加第三個實體。這樣,原來一?
個多對多的關系,現在變為兩個一對多的關系。要將原來兩個實體的屬性合理地分配到三個實體中去。這里的第三個?
實體,實質上是一個較復雜的關系,它對應一張基本表。一般來講,數據庫設計工具不能識別多對多的關系,但能處?
理多對多的關系。?
〖例3〗:在“圖書館信息系統”中,“圖書”是一個實體,“讀者”也是一個實體。這兩個實體之間的關系,是一?
個典型的多對多關系:一本圖書在不同時間可以被多個讀者借閱,一個讀者又可以借多本圖書。為此,要在二者之?
間增加第三個實體,該實體取名為“借還書”,它的屬性為:借還時間、借還標志(0表示借書,1表示還書),另外,?
它還應該有兩個外鍵(“圖書”的主鍵,“讀者”的主鍵),使它能與“圖書”和“讀者”連接。?
個人理解:一對多主外鍵,多對多中間表
7. 主鍵PK的取值方法?
PK是供程序員使用的表間連接工具,可以是一無物理意義的數字串, 由程序自動加1來實現。也可以是有物理意義?
的字段名或字段名的組合。不過前者比后者好。當PK是字段名的組合時,建議字段的個數不要太多,多了不但索引?
占用空間大,而且速度也慢。?
8. 正確認識數據冗余?
主鍵與外鍵在多表中的重復出現, 不屬于數據冗余,這個概念必須清楚,事實上有許多人還不清楚。非鍵字段的重?
復出現, 才是數據冗余!而且是一種低級冗余,即重復性的冗余。高級冗余不是字段的重復出現,而是字段的派生出現。?
〖例4〗:商品中的“單價、數量、金額”三個字段,“金額”就是由“單價”乘以“數量”派生出來的,它就是冗余,?
而且是一種高級冗余。冗余的目的是為了提高處理速度。只有低級冗余才會增加數據的不一致性,因為同一數據,可?
能從不同時間、地點、角色上多次錄入。因此,我們提倡高級冗余(派生性冗余),反對低級冗余(重復性冗余)。?
9. E--R圖沒有標準答案?
信息系統的E--R圖沒有標準答案,因為它的設計與畫法不是惟一的,只要它覆蓋了系統需求的業務范圍和功能內容,?
就是可行的。反之要修改E--R圖。盡管它沒有惟一的標準答案,并不意味著可以隨意設計。好的E—R圖的標準是:?
結構清晰、關聯簡潔、實體個數適中、屬性分配合理、沒有低級冗余。?
10 . 視圖技術在數據庫設計中很有用?
與基本表、代碼表、中間表不同,視圖是一種虛表,它依賴數據源的實表而存在。視圖是供程序員使用數據庫的?
一個窗口,是基表數據綜合的一種形式, 是數據處理的一種方法,是用戶數據保密的一種手段。為了進行復雜處理、?
提高運算速度和節省存儲空間, 視圖的定義深度一般不得超過三層。 若三層視圖仍不夠用, 則應在視圖上定義臨時表,?
在臨時表上再定義視圖。這樣反復交迭定義, 視圖的深度就不受限制了。?
對于某些與國家政治、經濟、技術、軍事和安全利益有關的信息系統,視圖的作用更加重要。這些系統的基本表完?
成物理設計之后,立即在基本表上建立第一層視圖,這層視圖的個數和結構,與基本表的個數和結構是完全相同。?
并且規定,所有的程序員,一律只準在視圖上操作。只有數據庫管理員,帶著多個人員共同掌握的“安全鑰匙”,?
才能直接在基本表上操作。請讀者想想:這是為什么??
11. 中間表、報表和臨時表?
中間表是存放統計數據的表,它是為數據倉庫、輸出報表或查詢結果而設計的,有時它沒有主鍵與外鍵(數據倉?
庫除外)。臨時表是程序員個人設計的,存放臨時記錄,為個人所用。基表和中間表由DBA維護,臨時表由程序員?
自己用程序自動維護。?
12. 完整性約束表現在三個方面?
域的完整性:用Check來實現約束,在數據庫設計工具中,對字段的取值范圍進行定義時,有一個Check按鈕,通?
過它定義字段的值城。?
參照完整性:用PK、FK、表級觸發器來實現。?
用戶定義完整性:它是一些業務規則,用存儲過程和觸發器來實現。?
13. 防止數據庫設計打補丁的方法是“三少原則”?
(1) 一個數據庫中表的個數越少越好。只有表的個數少了,才能說明系統的E--R圖少而精,去掉了重復的多余的?
實體,形成了對客觀世界的高度抽象,進行了系統的數據集成,防止了打補丁式的設計;?
(2) 一個表中組合主鍵的字段個數越少越好。因為主鍵的作用,一是建主鍵索引,二是做為子表的外鍵,所以組?
合主鍵的字段個數少了,不僅節省了運行時間,而且節省了索引存儲空間;?
(3) 一個表中的字段個數越少越好。只有字段的個數少了,才能說明在系統中不存在數據重復,且很少有數據冗?
余,更重要的是督促讀者學會“列變行”,這樣就防止了將子表中的字段拉入到主表中去,在主表中留下許?
多空余的字段。所謂“列變行”,就是將主表中的一部分內容拉出去,另外單獨建一個子表。這個方法很簡?
單,有的人就是不習慣、不采納、不執行。?
數據庫設計的實用原則是:在數據冗余和處理速度之間找到合適的平衡點。“三少”是一個整體概念,綜合觀點,?
不能孤立某一個原則。該原則是相對的,不是絕對的。“三多”原則肯定是錯誤的。試想:若覆蓋系統同樣的功?
能,一百個實體(共一千個屬性) 的E--R圖,肯定比二百個實體(共二千個屬性) 的E--R圖,要好得多。?
提倡“三少”原則,是叫讀者學會利用數據庫設計技術進行系統的數據集成。數據集成的步驟是將文件系統集成?
為應用數據庫,將應用數據庫集成為主題數據庫,將主題數據庫集成為全局綜合數據庫。集成的程度越高,數據?
共享性就越強,信息孤島現象就越少,整個企業信息系統的全局E—R圖中實體的個數、主鍵的個數、屬性的個數?
就會越少。?
提倡“三少”原則的目的,是防止讀者利用打補丁技術,不斷地對數據庫進行增刪改,使企業數據庫變成了隨意?
設計數據庫表的“垃圾堆”,或數據庫表的“大雜院”,最后造成數據庫中的基本表、代碼表、中間表、臨時表?
雜亂無章,不計其數,導致企事業單位的信息系統無法維護而癱瘓。?
“三多”原則任何人都可以做到,該原則是“打補丁方法”設計數據庫的歪理學說。“三少”原則是少而精的?
原則,它要求有較高的數據庫設計技巧與藝術,不是任何人都能做到的,因為該原則是杜絕用“打補丁方法”?
設計數據庫的理論依據。?
14. 提高數據庫運行效率的辦法?
在給定的系統硬件和系統軟件條件下,提高數據庫系統的運行效率的辦法是:?
(1) 在數據庫物理設計時,降低范式,增加冗余, 少用觸發器, 多用存儲過程。?
(2) 當計算非常復雜、而且記錄條數非常巨大時(例如一千萬條),復雜計算要先在數據庫外面,以文件系統方?
式用C++語言計算處理完成之后,最后才入庫追加到表中去。這是電信計費系統設計的經驗。?
(3) 發現某個表的記錄太多,例如超過一千萬條,則要對該表進行水平分割。水平分割的做法是,以該表主鍵?
PK的某個值為界線,將該表的記錄水平分割為兩個表。若發現某個表的字段太多,例如超過八十個,則?
垂直分割該表,將原來的一個表分解為兩個表。?
(4) 對數據庫管理系統DBMS進行系統優化,即優化各種系統參數,如緩沖區個數。?
(5) 在使用面向數據的SQL語言進行程序設計時,盡量采取優化算法。?
總之,要提高數據庫的運行效率,必須從數據庫系統級優化、數據庫設計級優化、程序實現級優化,這三?
個層次上同時下功夫。?
因此,考慮了以上條件之后,表設計約定規則如下:
二、事務跟存儲引擎
1.四種事務隔離級別:read uncommited, read commited(大多數db默認的),repeatable read(mysql默認), seriazable。
2.mysql是默認的auto commited, 也就是說每次查詢默認都是自動提交的(show variables like 'autocommited')。mysql可以通過set transaction isolatioin level命令來設置隔離級別,例如:set session transaction isolation level read commited。
3.mysql中像innodb采用mvcc(多版本并發控制)來處理并發。mvcc只工作在read commited,repeatable read這兩種事務隔離級別上。read uncommited隔離級別不兼容mvcc是因為在該級別得下的查詢,不讀取符合當前事務版本的數據行,而是最新版本的數據行。seriazable隔離級別不兼容MVCC,因為該級別下的讀操作會對每個返回行進行加鎖。
4.選擇存儲引擎,并發選用myisam,事務選擇innodb,myisam比innodb更容易出錯,出錯了恢復的時間也比較長。只有myisam支持全文檢索。
5.把表從一種存儲引擎轉到另一種引擎:
// ?1. ? ?alter table mytable engine=falcon; ?操作費時,可能會占用服務器的所有i/o處理能力。 // ?2. ? ?create table innodb_table like myisam_table; // ? ? ? ?alter table innodb_table engine=innodb; // ? ? ? ?insert into innodb_table select * from myisam_table;三、數據類型
1.盡可能的要把field定義為Not NULL, mysql比較難優化使用了可空列的查詢,它會使索引,索引統計更加復雜。可空列需要更多的存儲空間,還需要mysql內部進行特殊處理,當可空列被索引時,每條記錄都需要一個格外的字節。 即使要在表中存儲"沒有值"的字段,考慮使用0,特殊字段或者空字符串來代替。
2.datetime與timestamp能保存同樣的數據:精確度為秒,但是timestamp使用的空間只有datetime的一半,還能保存時區,擁有特殊的自動更新能力。但是timestamp保存的時間范圍要比datetime要小得多。mysql能存儲的最細的時間粒度為秒
3.mysql支持很多種別名,如bool,integer,nummeric.
4.float與double類型支持使用標準的浮點運算進行近似計算。 Decimal類型保存精確的小數,在>=mysql5.0,mysql服務器自身進行了decimal的運算,因為CPU不支持直接對它進行運算,所以慢一點。
5.mysql會把text與blob類型的列當成有實體的對象來進行保存。他們有各自的數據類型家族(tinytext,smalltext,text,mediumtext,longtext; blob類似); mysql對blob與text列排序方式和其他類型有所不同,它不會按照字符串的完整長度來排序。而只是按照max_sort_length規定的若干個字節來進行排序。
6.采用enum來代替字符串類型。mysql在內部把每個枚舉值都保存為整數。enum在內部是按照數字進行排序的,而不是按照字符串。enum最不好的就是字符串列表是固定的,添加和刪除必須使用alter table。
7.ip地址,一般會采用varchar(15)列來保存。事實上,IP地址是個無符號的32位整數,而不是字符串。mysql提供了inet_aton()和inet_nota()函數在證書與ip地址之間進行轉換。
四、索引
1.聚集索引不僅僅是一種單獨的索引類型,而且是一種存儲數據的方式。Innodb引擎的聚集索引實際上在同樣的結構中保存了B-Tree索引和數據行。當表有聚集索引時,它的數據行實際上保存在索引的葉子上。注意是存儲引擎來實現索引。
2.myisam與innodb數據布局:myisam索引樹(無論是主鍵索引還是非主鍵索引)葉子節點都是指向的數據行,而innodb中聚集索引,主鍵索引樹葉子節點就帶得有數據的內容,而非主鍵索引樹中葉子節點指向主鍵值,而不是數據的位置。
3.mysql有兩種產生排序結果的方式:使用文件排序,或者掃描有序的索引。目前只有myisam支持全文索引。
4.myisam表有表級鎖;myisam表不支持事務,實際上,myisam并不保證單條命令完成;myisam只緩存了mysql進程內部的索引,并保存在鍵緩存區內。OS緩存了表的數據;行被緊密的保存在一起,磁盤上的數據有很小的磁盤占用和快速的全表掃描。
5.innodb支持事務和四種事務隔離級別;在mysql5.0中,只有innodb支持外鍵;支持行級鎖與mvcc;所有的innodb表都是按照主鍵聚集的;所有索引(出開主鍵)都是按主鍵引用行;索引沒有使用前綴壓縮,因此索引可能比myisam大很多;數據轉載緩慢;阻塞auto_increment,也就是用表級鎖來產生每個auto_increment。
五、MYSQL性能分析
1.mysql提供了一個benchmark(int 循環次數,char* 表達式); 可以分析表達式執行所花時間。 例如:
? ? ? ? // select BENCHMARK(10000,SHA1('aaaaaaaaaaaaaaaa'))
2.mysql有兩種查詢日志:普通日志和慢速日志。
六、MYSQL高級特性
1.在mysql中,只有myisam存儲引擎支持全文索引。myisam全文索引是一種特殊的具有兩層結構的B樹。
2.存儲引擎事務在存儲引擎內部被賦予acid屬性,分布式(XA)是一種高層次事務,它可以歷喲內部個兩段提交的方式將acid屬性擴展到存儲引擎外部,甚至數據庫外部。階段1:通知所有提交者準備提交 階段2:通知所有參與者進行真正提交。
3.mysql 的字符集和校對規則有 4 個級別的默認設置:服務器級、數據庫級、表級和字段級。
總結
- 上一篇: MySQL幻读及解决方法
- 下一篇: 数据库中间件详解