淺談Mysql 表設計規范


本文首先探討下數據庫設計的三大范式,因為范式只是給出了數據庫設計的原則,並沒有告訴我們實際操作中應該怎樣操作,應該注意什么,所以我們還會談下實際工作中需要注意的具體操作問題。

三大范式

首先放出三大范式內容,然后再進行解釋:

第一范式:確保每列的原子性.,如果每列(或者每個屬性)都是不可再分的最小數據單元(也稱為最小的原子單元),則滿足第一范式.;(只要是關系型數據庫都滿足1NF)

第二范式:如果一個關系滿足第一范式,並且除了主鍵以外的其它列,都依賴於該主鍵,則滿足第二范式.;

第三范式:如果一個關系滿足第二范式,並且除了主鍵以外的其它列都不依賴於主鍵列,則滿足第三范式。

一范式就是屬性不可分割。屬性是什么?就是表中的字段。不可分割的意思就按字面理解就是最小單位,不能再分成更小單位了。這個字段只能是一個值,不能被拆分成多個字段。不過能不能分割並沒有絕對的答案,看需求,也就是看你的設計目標而定。

舉例:學生信息組成學生信息表,有姓名、年齡、性別、學號等信息組成。姓名不可拆分吧?所以可以作為該表的一個字段。但我要說這個表要在國外使用呢?人家姓和名要分開,都有特別的意義,所以姓名字段是可拆分的,分為姓字段和名字段。簡單來說,一范式是關系數據庫的基礎,但字段是否真的不可拆分,根據你的設計目標而定。

二范式就是要有主鍵,要求其他字段都依賴於主鍵。為什么要有主鍵?沒有主鍵就沒有唯一性,沒有唯一性在集合中就定位不到這行記錄,所以要主鍵。其他字段為什么要依賴於主鍵?因為不依賴於主鍵,就找不到他們。如果有同學不理解依賴這個詞,可以勉強用“相關”這個詞代替,也就是說其他字段必須和它們的主鍵相關。因為不相關的東西不應該放在一行記錄里。

舉例:學生信息組成學生表,姓名可以做主鍵么?不能!因為同名的話,就不唯一了,所以需要學號這樣的唯一編碼才行。那么其他字段依賴於主鍵是什么意思?就是“張三”同學的年齡和性別等字段,不能存儲別人的年齡性別,必須是他自己的,因為張三的學號信息就決定了,這行記錄歸張三所有,不能給無關人員使用。

三范式就是要消除傳遞依賴,方便理解,可以看做是“消除冗余”。消除冗余應該比較好理解一些,就是各種信息只在一個地方存儲,不出現在多張表中。比如說大學分了很多系(中文系、英語系、計算機系……),這個系別管理表信息有以下字段組成:系編號,系主任,系簡介,系架構。那么再回到學生信息表,張三同學的年齡、性別、學號都有了,我能不能把他的系編號,系主任、系簡介也一起存着?如果你問三范式,當然不行,因為三范式不同意。因為系編號,系主任、系簡介已經存在系別管理表中,你再存入學生信息表,就是冗余了。三范式中說的傳遞依賴,就出現了。這個時候學生信息表中,系主任信息是不是依賴於系編號了?而這個表的主鍵可是學號啊!所以按照三范式,處理這個問題的時候,學生表就只能增加一個系編號字段。這樣既能根據系編號找到系別信息,又避免了冗余存儲的問題。

還有要強調的就是所謂的范式,是用來學習參考的,設計的時候根據情況,未必一定要遵守。因為在數據庫數據量特別大,並且訪問並發也大的情況下,可能要采用反范式設計來提高數據庫響應速度,不過這里不在過多討論,有興趣的同學可以到這個網址查看具體內容,該文檔針對mysql的優化做了詳細說明:https://wenku.baidu.com/view/aa43ecc3aa00b52acfc7ca94.html

實際操作規范(mysql)

  • 表設計

  1. 庫名、表名、字段名必須使用小寫字母,“_”分割,且名稱長度不超過12個字符並且要做到見名知意。

  2. 建議使用InnoDB存儲引擎。

  3. 存儲精確浮點數必須使用DECIMAL替代FLOAT和DOUBLE。

  4. 建議使用UNSIGNED存儲非負數值。

  5. 建議使用INT UNSIGNED存儲IPV4

  6. 整形定義中不添加長度,比如使用INT,而不是INT(4)。

  7. 使用短數據類型,比如取值范圍為0-80時,使用TINYINT UNSIGNED。

  8. 不建議使用ENUM類型,使用TINYINT來代替。

  9. 盡可能不使用TEXT、BLOB類型。

  10. VARCHAR(N),N表示的是字符數不是字節數,比如VARCHAR(255),可以最大可存儲255個漢字,需要根據實際的寬度來選擇N。

  11. VARCHAR(N),N盡可能小,因為MySQL一個表中所有的VARCHAR字段最大長度是65535個字節,進行排序和創建臨時表一類的內存操作時,會使用N的長度申請內存

  12. 表字符集選擇UTF8。

  13. 使用VARBINARY存儲變長字符串。

  14. 存儲年使用YEAR類型,存儲日期使用DATE類型,存儲時間(精確到秒)建議使用TIMESTAMP類型,因為TIMESTAMP使用4字節,DATETIME使用8個字節。

  15. 建議字段定義為NOT NULL。

  16. 將過大字段拆分到其他表中。

  17. 禁止在數據庫中使用VARBINARY、BLOB存儲圖片、文件等。

  • 索引

  1. 索引名稱必須使用小寫,非唯一索引必須按照“idx_字段名稱_字段名稱[_字段名]”進行命名,唯一索引必須按照“uniq_字段名稱_字段名稱[_字段名]”進行命名。

  2. 索引中的字段數建議不超過5個。

  3. 單張表的索引數量控制在5個以內。

  4. 唯一鍵由3個以下字段組成,並且字段都是整形時,使用唯一鍵作為主鍵。

  5. 沒有唯一鍵或者唯一鍵不符合4中的條件時,使用自增(或者通過發號器獲取)id作為主鍵。

  6. 唯一鍵不和主鍵重復。

  7. 索引字段的順序需要考慮字段值去重之后的個數,個數多的放在前面。

  8. ORDER BY,GROUP BY,DISTINCT的字段需要添加在索引的后面。

  9. 使用EXPLAIN判斷SQL語句是否合理使用索引,盡量避免extra列出現:Using File Sort,UsingTemporary。

  10. UPDATE、DELETE語句需要根據WHERE條件添加索引。

  11. 不建議使用%前綴模糊查詢,例如LIKE “%weibo”。

  12. 對長度過長的VARCHAR字段建立索引時,添加crc32或者MD5 Hash字段,對Hash字段建立索引。

  13. 合理創建聯合索引(避免冗余),(a,b,c)相當於 (a) 、(a,b) 、(a,b,c)。

  14. 合理利用覆蓋索引。

  15. SQL變更需要確認索引是否需要變更並通知DBA。

  • SQL語句

  1. SQL語句中IN包含的值不應過多。

  2. UPDATE、DELETE語句不使用LIMIT。

  3. WHERE條件中必須使用合適的類型,避免MySQL進行隱式類型轉化。

  4. SELECT語句只獲取需要的字段。

  5. SELECT、INSERT語句必須顯式的指明字段名稱,不使用SELECT *,不使用INSERTINTO table。

  6. 使用SELECT column_name1, column_name2 FROM table WHERE[condition]而不是SELECT column_name1 FROM table WHERE[condition]和SELECT column_name2 FROM table WHERE [condition]。

  7. WHERE條件中的非等值條件(IN、BETWEEN、<、<=、>、>=)會導致后面的條件使用不了索引。

  8. 避免在SQL語句進行數學運算或者函數運算,容易將業務邏輯和DB耦合在一起。

  9. INSERT語句使用batch提交(INSERT INTO tableVALUES,,……),values的個數不應過多。

  10. 避免使用存儲過程、觸發器、函數等,容易將業務邏輯和DB耦合在一起,並且MySQL的存儲過程、觸發器、函數中存在一定的bug。

  11. 避免使用JOIN。

  12. 使用合理的SQL語句減少與數據庫的交互次數。

  13. 不使用ORDER BY RAND,使用其他方法替換。

  14. 建議使用合理的分頁方式以提高分頁的效率。

  15. 統計表中記錄數時使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。

  16. 禁止在從庫上執行后台管理和統計類型功能的QUERY。

  • 散表

  1. 每張表數據量建議控制在5000w以下。

  2. 可以結合使用hash、range、lookup table進行散表。

  3. 散表如果使用md5(或者類似的hash算法)進行散表,表名后綴使用16進制,比如user_ff。

  4. 推薦使用CRC32求余(或者類似的算術算法)進行散表,表名后綴使用數字,數字必須從0開始並等寬,比如散100張表,后綴從00-99。

  5. 使用時間散表,表名后綴必須使用特定格式,比如按日散表user_20110209、按月散表user_201102。

文:https://www.yidianzixun.com/article/0GJKj9Xz?title_sn/0&s=9&appid=xiaomi&ver=3.9.6.0&utk=4lxc4q7c


免責聲明!

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



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