1. 基礎
1.1. 數據庫設計步驟
- 需求分析(根據數據的屬性和特點設置數據類型);
- 邏輯設計(ER 圖);
- 物理設計(選擇開發環境);
- 維護優化(新建表、索引、拆分);
1.2. 術語
- 關係
- 一個關係對應通常所說的一張表;
- 元組
- 表中的一行爲一個元組;
- 屬性
- 表中的一列爲一個屬性;每一個屬性有一個名稱爲屬性名(表字段);
- 候選碼
- 表中的某個屬性級,它可以唯一確定一個元組;
- 主碼
- 一個關係有多個候選碼,選定其中一個爲主碼;
- 域
- 屬性的取值範圍(e.g.: 真假:Y/N...);
- 分量
- 元組中的一個屬性值;
1.3. ER 圖注
矩形:實體集;
菱形:關係集;
橢圓:屬性;
線:關係;
2. 需求分析
2.1. 要點
- 存儲數據是什麼;
- 數據存儲特點(時效性數據【定期清理機制】;沒有時效性的數據);
- 數據的生命週期(增長速度快,量大,應採用拆表分表方式設計)
2.2. 表的實體關係
- 實體及實體關係(1:1,1:N,N:N);
- 實體所包含屬性(存儲特點,1次1行、N行,DIU結合操作存儲...);
- 那些屬性或屬性組合可以唯一標識一個實體(主鍵,外鍵關係);
- 存儲特性(是否永久存儲);
合理分庫、分表。按期歸檔,使數據庫高效運轉。
3. 邏輯設計
3.1. 數據冗餘
- 數據冗餘
- 指相同的數據在多個地方存在(多個表存在,一個表多個字段意義相同),或者說某個列可以由其他列計算得到,這樣就說表中存在着數據冗餘(不符合範式要求既有數據冗餘)。
可包括——
- 插入異常 (insert);
- 更新異常 (update);
- 刪除異常 (delect);
3.2. 設計範式
3.2.1. 第一範式 (1NF)
- 定義
- 數據庫表中所有字段均爲 單一屬性,且 不可再分;
- 補充
- 單一屬性指由基本的數據類型(如:整數、浮點數、字符串等)構成;
- 釋義
- 表都必須是二維表;不可表中套表;
3.2.2. 第二範式 (2NF)
- 定義
- 數據庫表中不存在非關鍵字段對任一候選關鍵字段的 部分函數依賴;
- 補充
- 部分函數依賴是指存在着組合關鍵字中的某一關鍵字決定非關鍵字的情況;
- 釋義
- 表都必須是單關鍵字段的表;
- 問題
- 不符合 2NF 時可能產生的問題:插入異常、更新異常、刪除異常、數據冗餘;
- 解決
- 拆分成單關鍵字的表(兩個表 + 一個關係表);
3.2.3. 第三範式 (3NF)
- 定義
- 若數據表不存在非關鍵字段、也不存在對任意候選關鍵字段的 傳遞函數依賴 則符合 3NF;
- 釋義
- 不存在非主屬性部分函數依賴於碼,同時不傳遞依賴與碼;
- 問題
- 不符合 3NF 時可能產生的問題:插入異常、更新異常、刪除異常、數據冗餘;
- 解決
- 拆分成單關鍵字的表(兩個表 + 一個關係表);
3.2.4. BC 範式 (BCNF)
- 定義
- 在 3NF 基礎上,若不存在任何字段對任一候選關鍵字段的傳遞函數依賴則符合 BCNF;
- 釋義
- 若有複合關鍵字,則複合關鍵字之間不能存在函數依賴關係(不可一詞多義);
3.2.5. 第四範式
暫無簡介
3.2.6. 第五範式
暫無簡介
4. 物理設計
4.1. 設計步驟
- 選擇合適的數據庫管理系統:
a. 商業數據庫(企業級項目):Oracle、SQL Server;
b. 開源數據庫(互聯網項目):MySQL、PgSQL; - 設定數據庫表及字段命名、數據庫設計規範;
- 由所選 DBMS 選用合適的數據類型;
- 反範式設計:過分要求範式設計必定會增加關係度的複雜,應在範式與簡約節時的原則上找到平衡;4.2. MySQL 初步
4.2.1. 存儲引擎
大多數互聯網應用建議使用 Innodb;
4.2.2. 命名規範
- 某些 DBMS 對大小寫敏感,可以設置;
- 語義化;
- 長命名以消除歧義;
4.2.3. 字段類型選用
- 數據查詢性能:對數據進行比較(查詢條件、JOIN 條件及排序分組等)操作時,同樣的數據,數字比字符處理要快;
- 存儲空間開銷:在數據庫中,數據處理以頁爲單位,列的長度越小,字節越小,利於 I/O 性能提升(單頁 SQL Server: 8K、MySQL: 16K);
- 數據類型優先級:
數字
>日期
=二進制類型
>字符類型
;相同級別的數據類型,優先選擇佔用空間小的數據類型;
4.2.4. 字符:char/varchar
- 如果列中要存儲的數據長度差不多一致,則使用
char
;否則考慮varchar
(e.g.: 手機號/身份證號碼); - 如果列中的最大數據長度小於 50 Byte,一般考慮用
char
(如果這個列很少用,則基於節省空間和減少 I/O 的考慮,也可以用varchar
); - 一般不宜定義大於 50 Byte 的
char
類型列;
4.2.5. 數字:decimal/float
decimal
用於存儲精確數據,而float
只能用於存儲非精度數據;- 由於
float
的存儲空間開銷一般比demimal
小;故非精度數據優先選擇float
;
4.2.6. 時間:int/datetime**
int
:字段長度比datetime
小;使用不方便,要進行函數轉換,且只能存儲到 2038-01-19 11:14:07;使用、查詢少宜用int
;datetime
:查詢頻繁的時間戳;- 需要存儲的時間粒度:年月日時分秒周;
4.2.7. 其它
- 字符
- 計算機中使用的文字和符號;
- 字節
- 計量單位;
- ASCII 編碼中,一個英文字母(不分大小寫)佔一個字節的空間,一箇中文漢字佔兩個字節的空間。一個二進制數字序列,在計算機中作爲一個數字單元,一般爲 8 位二進制數,換算爲十進制。最小值 0,最大值 255。
- UTF-8 編碼中,一個英文字符等於一個字節,一箇中文(含繁體)等於三個字節。
- Unicode 編碼中,一個英文等於兩個字節,一箇中文(含繁體)等於兩個字節。符號:英文標點佔一個字節,中文標點佔兩個字節。舉例:英文句號“.”佔 1 個字節的大小,中文句號“。”佔 2 個字節的大小。
- UTF-16 編碼中,一個英文字母字符或一個漢字字符存儲都需要 2 個字節(Unicode 擴展區的一些漢字存儲需要4個字節)。
- UTF-32 編碼中,世界上任何字符的存儲都需要 4 個字節。
4.2.8. 主鍵選用
選擇原則
- 區分業務主鍵和數據庫主鍵:業務主鍵用於標識業務數據,進行表與表之間的關聯;數據庫主鍵爲了優化數據存儲。
- 根據數據庫的類型,考慮主鍵是否要順序增長:有些數據庫是按主鍵的順序邏輯存儲的。
- 主鍵的字段類型所佔用空間要儘可能的小:對於使用聚集索引方式存儲的表,每個索引後都會附加主鍵信息。
避免使用外鍵約束
- 降低數據導入的效率;
- 增加維護成本;
- 雖然不建議使用外鍵約束,但是相關聯的列上一定要建立索引;
避免使用觸發器
- 降低數據導入的效率;
- 可能會出現意想不到的數據異常;
- 使業務邏輯變的複雜;
關於預留字段
- 無法準確的知道預留字段的類型;
- 無法準確的知道預留字段中所存儲的內容;
- 後期維護預留字段需要成本;
- 嚴禁使用預留字段;
4.2.9. 反範式化設計
爲了性能和讀取效率的考慮而適當的對第三範式的要求進行違反,允許存在少量的數據冗餘;即以空間換時間。
- 減少表的關聯數量;
- 增加數據的讀取效率;
- 反範式化一定要適度;
5. 維護優化
5.1. 維護要點
- 維護數據字典;
- 維護索引;
- 維護表結構;
- 在適當的時候對錶進行水平拆分或垂直拆分;
5.2. 維護數據字典
- 使用第三方工具;
- 利用數據庫本身的備註字段來維護數據字典;
5.3. 維護索引
- 建立索引
- 出現在
where
從句,group by
從句,order by
從句中的列; - 可選擇性高的列要放到索引的前面;
- 索引中不要包括太長的數據類型(儘量數字,日期,單字節字符類型等);
- 出現在
- 維護索引
- 索引不是越多越好,多餘的索引會降低讀寫效率;
- 定期維護索引片段;
- SQL 語句中不要使用強制索引關鍵字(索引會隨着數據量的變化而變得不適應);
5.4. 維護表結構
注意事項
- 使用在線變更表結構工具;
MySQL 5.5 之前以使用 pt-online-schema-change;
MySQL 5.6 之後本身支持在線表結構的變更; - 同時對數據字典進行維護;
- 控制表的寬度和大小(表字段的大小控制,表數據量的分區,拆分處理等);
適合的操作
- 批量操作和逐條操作;
- 禁止使用
select *
這樣的查詢(把不必要的字段也查詢出來,浪費 I/O); - 控制使用用戶自定義函數(索引失效);
- 不要使用數據庫中的全文索引;
5.5. 表的拆分
-
垂直拆分
- 經常一起查詢的列放到一起
- Text、Blob 等大字段拆分到附加表中
-
水平拆分
- Hash Key 拆分;
- 時區段域拆分;
- 表業務類型拆分;