mysql表設計原則


0.三大范式及反范式

◆ 第一范式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。 
◆ 第二范式(2NF):首先是 1NF,另外包含兩部分內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。 
◆ 第三范式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況。 
第二范式(2NF)和第三范式(3NF)的概念很容易混淆,區分它們的關鍵點在於,2NF:非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分;3NF:非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。
 
范式的優點:
1)范式化的數據庫更新起來更加快;
2)范式化之后,只有很少的重復數據,只需要修改更少的數據;
3)范式化的表更小,可以在內存中執行;
4)很少的冗余數據,在查詢的時候需要更少的distinct或者group by語句。
范式的缺點:
1)范式化的表,在查詢的時候經常需要很多的關聯,因為單獨一個表內不存在冗余和重復數據。這導致,稍微復雜一些的查詢語句在查詢范式的schema上都可能需要較多次的關聯。這會增加讓查詢的代價,也可能使一些索引策略無效。因為范式化將列存放在不同的表中,而這些列在一個表中本可以屬於同一個索引。
 
反范式的優點:
1)可以避免關聯,因為所有的數據幾乎都可以在一張表上顯示;
2)可以設計有效的索引;
反范式的缺點:
3)表格內的冗余較多,刪除數據時候會造成表有些有用的信息丟失。
所以在設計數據庫時,要注意混用范式化和反范式化。
 
下面是表單設計中一些經常要注意的地方:
 

1.適度冗余, 讓query盡量減少join

雖然optimizer會對query進行一定的優化,但有時候遇見復雜的join,優化效果並不令人滿意,再加上本來join的性能開銷,所以需要盡量的減少join,而需要通過冗余來實現。比如:有兩個數據表分別為用戶信息表和用戶發帖表,在展示發帖列表時,如果沒有冗余的話,兩個表要join以取得想要的發帖信息和用戶昵稱,但如果考慮冗余,用戶昵稱占用空間不大,如果在發帖表里增加這么一個字段的話,在展示列表時就不用做join操作了,性能會得到很大的改善。
但冗余也會帶來一些問題,比如在發帖表里增加了用戶昵稱字段,就得維護兩份用戶昵稱數據,為了保證數據的一致性,在用戶昵稱發生改變時,就得向兩個表做更新操作,程序中就得做更多的處理。但相比的話,更新頻率顯然不及查詢頻率,這樣通過增加少量的更新操作會換來更大的性能提升,這也是在項目中經常采用的優化手段。
 

2. 大字段垂直分拆

所謂的大字段,沒有一個很嚴格的標准,常用的是如果一個字段的大小占整條記錄的50%以上,我們就視為其為大字段。大字段垂直分拆相比適度冗余是完全相反的操作,適度冗余是將別的表中的字段放進一個表中,而大字段分拆是將自身的大字段拆分出去放進另一個表中。
這兩個優化策略貌似是矛盾的,但要根據具體的應用場景來分析,適度冗余是因為在頻率較高的查詢中要使用該字段,為了減少join的性能開銷。而大字段垂直分拆是將在查詢中不使用的大字段拿出去,雖然不使用該字段但mysql在查詢時並不是只需要訪問需要查詢的那幾個字段,而是讀取所有的字段,所以即使不使用字段,mysql也會讀取該字段,為了節省IO開銷,所以將查詢中不常使用的大字段分拆出去。比如:拿博客系統為例,常用的作法是將博客內容從博客列表里分拆出去建立一個博客內容表,因為訪問博客列表時並不需要讀取博客內容,分拆出去之后,訪問博客列表的性能將會大大的提升。但同時訪問博客內容時就得做一次join操作了,性能對比的話,join操作兩個表是一對一的關系,性能開銷會很低。
 

3. 大表水平分拆

舉例說明:在一個論壇系統里,管理員經常會發一些帖子,這些帖子要求在每個分類列表里都要置頂。
設計方案一:在發帖表里增加一列用來標示是否是管理員發帖,這樣在每個分類列表展示時就需要對發帖表查詢兩次,一次是置頂帖,一次是普通帖,然后將兩次結果合並。如果發帖表內容較大時,查詢置頂帖的性能開銷會比較大。
設計方案二:將置頂帖存放在一個單獨的置頂表里。因為置頂帖數量相比會很少,但訪問頻率很高,這樣從發帖表里分拆開來,訪問的性能開銷會少很多。
 

4.選擇合適的數據類型

要選擇合適的數據類型必須要先了解不同數據類型間的差異。
數字類型有整數類型和浮點數類型,還有一類是通過二進制格式以字符串來存放的數字類型,如DECIMAL(size,d),其存放長度主要通過定義的size決定,size定義多大,則實際存放就有多長。默認的size為10,d為0。這種類型的存放長度較長而且完全可以用整形來代替實現,所以不推薦使用。
時間類型主要使用DATE,DATETIME和TIMESTAMP三種類型,TIMESTAMP占用存儲空間最少,只要4個字節,其它兩種類型都要占用8個字節。從存儲內容來看,TIMESTAMP只能存儲1970年之后的時間,另外兩種都能存儲從1001開始的時間。
特別要說明的是varchar類型,varchar(size),在mysql5.0.3之前size表示的是字節數,mysql5.0.3之后size表示的是字符數。這里我們只關注mysql5.0.3之后的表示,size表示的字符數最大限制和字符集有關,如果是gbk編碼,最大長度為(65535-1-2)/2=32766,減1的原因是實際行存儲從第二個字節開始,減2的原因是varchar頭部的2個字節表示長度,除2因為是gbk編碼;如果是utf8編碼,最大長度為(65535-1-2)/3=21844。
 
如果數據量一樣,但數據類型更小的話,數據存放同樣的數據就會占用更少的空間,這樣檢索同樣的數據所帶來的IO消耗自然會降低,性能也就很自然的得到提升。此外,mysql對不同類型的數據,處理方式也不一樣,比如在運算或者排序操作中,越簡單的數據類型操作性能越高,所以對於要頻繁進行運算或者排序的字段盡量選擇簡單的數據類型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM