一、范式和反范式
優秀的庫表設計是高性能數據庫的基礎。如何才能設計出高性能的庫表結構呢?這里必須要提到數據庫范式。范式是基礎規范,反范式是針對性設計。
1.1、范式
范式是設計數據庫結構過程中所要遵循的規則和指導方法
其實范式有很多,目前關系數據庫有六種范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又稱完美范式)。滿足最低要求的范式是第一范式(1NF)。在第一范式的基礎上進一步滿足更多規范要求的稱為第二范式(2NF),其余范式以次類推。一般來說,數據庫只需滿足第三范式(3NF)就行了。但是一般我們就用到前三個范式
第一范式(確保每列保持原子性)
第一范式是最基本的范式。如果數據庫表中的所有字段值都是不可分解的原子值,就說明該數據庫表滿足了第一范式。
第一范式的合理遵循需要根據系統的實際需求來定。比如某些數據庫系統中需要 用到“地址”這個屬性,本來直接將“地址”屬性設計成一個數據庫表的字段就行。 但是如果系統經常會訪問“地址”屬性中的“城市”部分,那么就
非要將“地址”這個屬 性重新拆分為省份、城市、詳細地址等多個部分進行存儲,這樣在對地址中某一 部分操作的時候將非常方便。這樣設計才算滿足了數據庫的第一范式,如下表所 示。
上表所示的用戶信息遵循了第一范式的要求,這樣在對用戶使用城市進行分類的 時候就非常方便,也提高了數據庫的性能。
第二范式(確保表中的每列都和主鍵相關)
第二范式在第一范式的基礎之上更進一層。第二范式需要確保數據庫表中的每一 列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。 也就是說在一個數據庫表中,一個表中只能保存一種數據,
不可以把多種數據 保存在同一張數據庫表中。
比如要設計一個訂單信息表,因為訂單中可能會有多種商品,所以要將訂單編 號和商品編號作為數據庫表的聯合主鍵。
第三范式(確保每列都和主鍵列直接相關,而不是間接相關)
第三范式需要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。
比如在設計一個訂單數據表的時候,可以將客戶編號作為一個外鍵和訂單表建立 相應的關系。而不可以在訂單表中添加關於客戶其它信息(比如姓名、所屬公司 等)的字段。
總結:1NF:無重復的列,屬性不可以拆分(強調列的原子性,比如家庭電話和個人電話需要拆開)
2NF:屬性完全依賴於主鍵
3NF:屬性不傳遞依賴於其他非主屬性
1.2、范式的優點缺點
優點:避免數據冗余,減少數據的空間,數據變更速度更快
缺點:范式等級越高,表的數量越多,獲取數據時表關聯過多,性能較差
1.3、反范式
范式設計的表無法滿足性能需求時,需要根據業務場景,在范式的基礎上靈活設計
1.業務場景
2.響應時間
3.字段冗余
1.4、反范式和范式的對比
二、基礎規范和命名規范
2.1、基礎規范
想要發揮 MySQL 的最佳性能,需要遵循 3 個基本使用原則。
1.回歸存儲的基本職能(MySQL 數據庫只用於數據的存儲,不進行數據的復雜計算,不承載業務邏輯,確保存儲和計算分離)
2.查詢時盡量單表查詢,減少跨庫查詢和多表關聯
3.杜絕大事務、大SQL、大批量、大字段等性能殺手
大事務:運行步驟較多,涉及的表和字段較多,容易造成資源的爭搶,甚至形成死鎖。一旦事務回滾,會導致資源占用時間過長。
大 SQL:復雜的 SQL 意味着過多的表的關聯,MySQL 數據庫處理關聯超過 3 張表以上的 SQL 時,占用資源多,性能低下。
大批量:意味着多條 SQL 一次性執行完成,必須確保進行充分的測試,並且在業務低峰時段或者非業務時段執行。
大字段:blob、text 等大字段,盡量少用。必須要用時,盡量與主業務表分離,減少對這類字段的檢索和更新。
下面具體講解數據庫的基本設置規則:
- 必須指定默認存儲引擎為 InnoDB,並且禁用 MyISAM 存儲引擎,隨着 MySQL 8.0 版本的發布,所有的數據字典表都已經轉換成了 InnoDB,MyISAM 存儲引擎已成為了歷史。
- 默認字符集 UTF8mb4,以前版本的 UTF8 是 UTF8mb3,未包含個別特殊字符,新版本的 UTF8mb4 包含所有字符,官方強烈建議使用此字符集。
- 關閉區分大小寫功能。設置 lower_case_tables_name=1,即可關閉區分大小寫功能,即大寫字母 T 和小寫字母 t 一樣。
- 開啟 per-table 表空間,開啟后,每張業務表會單獨創建一個獨立於系統表空間的表空間,便於空間的回收,數據的遷移。
這里在實踐中有個小問題,如何讓系統中區分大小寫的庫表轉換為不區分大小寫的庫表呢?因為要修改底層數據,還是比較麻煩的,操作步驟如下:
MySQL dump 導出數據庫。
修改參數 lower_case_tables_name=1。
導入備份數據時,必須停止數據庫,停止業務,影響非常大。
禁用功能
MySQL 數據庫提供的功能很全面,但並不是所有的功能性能都高效。
存儲過程、觸發器、視圖、event。為了存儲計算分離,這類功能盡量在程序中實現。這些功能非常不完整,調試、排錯、監控都非常困難,相關數據字典也不完善,存在潛在的風險。一般在生產數據庫中,禁止使用。
lob、text、enum、set。這些字段類型,在 MySQL 數據庫的檢索性能不高,很難使用索引進行優化。如果必須使用這些功能,一般采取特殊的結構設計,或者與程序結合使用其他的字段類型替代。比如:set 可以使用整型(0,1,2,3)、注釋功能和程序的檢查功能集合替代。
2.2、命名規范
- 名稱的字符范圍為:a-z,0-9和_(下划線)
- 所有表名小寫
- 不允許使用-(橫杠)、空格
- 不允許其他字符作為名稱例如:@&*%¥#等等
庫名:1位數據庫類型代碼+項目簡稱+識別代碼+序號
表名:
字段名:
三、Innodb表要求
- 主鍵列,UNSIGNED證書,使用auto_increment(這個如果在實際項目中不一定的,大多數不會用自增,因為在分庫分表會有問題,會用雪花算法計算id)
- 必須添加comment注解(主要是為了方便他人理解)
- 必須顯式指定engine(引擎)
- 表必備三字段:id,xxx_create,xxx_modified(主鍵id,創建時間,更新時間)
四、字段設計要求
數據值進行參考
- 合理的類型,最短的長度,NotNULL
- 表字段少而精
- 單表個數必須控制在2000個以內
- 單表分表個數必須控制在1024個以內
- 單表字段數上限控制在20-50
總結
- 以高性能為目標,庫表設計以范式為主,根據特殊業務場景使用反范式,允許必要的空間換時間。
- 規范數據庫的使用原則,統一規范命名,減少性能隱患,減少隱式轉換。
- 高性能表設計的原則:合適的字段、合適的長度、NOT NULL。
- 從不同角度思考 IP、timestamp 的轉換,拓寬設計思路。
- 規范的命名可提高可讀性,反范式設計可提高查詢性能。