這是我參與8月更文挑戰的第1天,活動詳情查看:8月更文挑戰mysql
「 這篇文章主要爲了說明規矩要遵照,可是也別這麼死板,要知道因場景不一樣而變化。瞭解各自的優缺點,在不一樣業務中根據需求選擇使用。 」sql
咱們在項目上進行數據庫設計的時候要求遵照三範式,爲何會約束三範式呢:爲了減小數據冗餘。數據庫
回憶下是哪三範式:緩存
全部屬性具備原子性,列不可分割。markdown
例如家庭地址(xx省xx市xx地址),家庭地址做爲字段就是非原子的,能夠拆分紅字段省份,城市,地址。數據庫設計
在第一範式的基礎上,要求全部非主鍵字段徹底依賴主鍵,不能產生部分依賴。post
一個數據庫表中,一個表中只能保存一種數據,不能夠把多種數據保存在同一張數據庫表中。網站
在第二範式的基礎上,保證每列都和主鍵直接相關,不存在傳遞依賴spa
表中的字段和主鍵直接對應不依靠其餘中間字段。傳遞依賴:A--->B--->C。設計
優勢:
缺點:
阿里開發手冊中規定表join關聯不能超過3個,主要緣由就是數據量大的時候join查詢很是慢,可是也不必定不能關聯多個,具體問題具體分析,數據量少的時候多張表關聯也沒影響的。
優勢:
數據都在一張表中,能夠很好的避免關聯。
若是不須要關聯,則對大部分查詢最差的狀況---即便表沒有使用索引,是全表掃描。當數據比內存大時,可能比關聯要快得多,由於這樣避免了隨機I/O(全表掃描基本上是順序I/O,但不是100%的和引擎有關).
單表能夠更有效的使用索引策略。
缺點:
實際上徹底範式或者徹底反範式都是理論上的。在實際的項目開發中,基本都是混用的,沒有嚴格的規定。
例A: 假設有一個網站,容許用戶發送消息,並且其中一些用戶是VIP,如今想查看VIP用戶的近10條信息。
查詢sql:
SELECT message.message_text FROM message INNER JOIN USER ON message.user_id = USER.user_id WHERE USER.user_type = 'VIP' ORDER BY message.published DESC LIMIT 10;
複製代碼
上面sql須要表關聯,mysql須要掃描message 表的日期published的索引,對於每一行找到的數據都要到user表檢索是否是VIP用戶,若是VIP只是很小的一部分,這個效率就很低下了。另外一種執行計劃是先從user表開始,找全部VIP用戶獲取並排序,這種可能更糟糕。
徹底的反範式,須要在message表中存儲user數據,就會存在message數據操做影響user數據的問題。
混用範式和反範式:修改message表結構增長用戶類型字段user_type, 如:message(message_id,user_id,message_text,published,user_type),這種設計能夠避免徹底範式化帶來的表關聯查詢,也避免了徹底反範式的插入刪除問題(即便沒有消息用戶的信息也不會丟失)。
例B: 若是部分需求是查詢的結果須要排序,從父表中冗餘一些數據到子表更方便設計索引,提升查詢效率。
例C: 對於緩存衍生值也是有效的,若是須要顯示每一個用戶發了多少消息(論壇發帖),每次須要執行一個統計的自查詢計算,其實能夠在user表中增長消息數量的字段,當用戶發送消息的時候更新這個值(須要平衡更新和查詢哪一個更好)。
以上只是爲了說明範式和反範式以及混用範式而舉的例子,可是實際開發中仍是要根據業務來選擇怎麼使用。
在表設計中,使用範式也好,反範式也好,不該該有嚴格的限制,該用哪一種就使用哪一種或者二者結合使用。
mysql進階系列持續更新中