重點在於反模式的回答。實際開發中,不會嚴格遵照三範式。數據庫
數據庫範式是爲解決關係數據庫中數據冗餘、更新異常、插入異常、刪除異常問題而引入的。簡單的理解,數據庫範式能夠避免數據冗餘,減小數據庫的空間,而且減輕維護數據完整性的麻煩。緩存
第一範式,強調屬性的原子性約束,要求屬性具備原子性,不可再分解。數據庫設計
舉個例子,活動表(活動編碼,活動名稱,活動地址),假設這個場景中,活動地址能夠細分爲國家、省份、城市、市區、位置,那麼就沒有達到第一範式。性能
第二範式,強調記錄的惟一性約束,表必須有一個主鍵,而且沒有包含在主鍵中的列必須徹底依賴於主鍵,而不能只依賴於主鍵的一部分。編碼
舉個例子,版本表(版本編碼,版本名稱,產品編碼,產品名稱),其中主鍵是(版本編碼,產品編碼),這個場景中,數據庫設計並不符合第二範式,由於產品名稱只依賴於產品編碼。存在部分依賴。因此,爲了使其知足第二範式,能夠改形成兩個表:版本表(版本編碼,產品編碼)和產品表(產品編碼,產品名稱)。設計
第三範式,強調屬性冗餘性的約束,即非主鍵列必須直接依賴於主鍵。排序
舉個例子,訂單表(訂單編碼,顧客編碼,顧客名稱),其中主鍵是(訂單編碼),這個場景中,顧客編碼、顧客名稱都徹底依賴於主鍵,所以符合第二範式,可是顧客名稱依賴於顧客編碼,從而間接依賴於主鍵,因此不能知足第三範式。爲了使其知足第三範式,能夠拆分兩個表:訂單表(訂單編碼,顧客編碼)和顧客表(顧客編碼,顧客名稱),拆分後的數據庫設計,就能夠徹底知足第三範式的要求了。索引
值得注意的是,第二範式的側重點是非主鍵列是否徹底依賴於主鍵,仍是依賴於主鍵的一部分。第三範式的側重點是非主鍵列是直接依賴於主鍵,仍是直接依賴於非主鍵列。開發
範式能夠避免數據冗餘,減小數據庫的空間,減輕維護數據完整性的麻煩。文檔
然而,經過數據庫範式化設計,將致使數據庫業務涉及的表變多,而且可能須要將涉及的業務表進行多表鏈接查詢,這樣將致使性能變差,且不利於分庫分表。所以,出於性能優先的考量,可能在數據庫的結構中須要使用反模式的設計,即空間換取時間,採起數據冗餘的方式避免表之間的關聯查詢。至於數據一致性問題,由於難以知足數據強一致性,通常狀況下,使存儲數據儘量達到用戶一致,保證系統通過一段較短的時間的自我恢復和修正,數據最終達到一致。
須要謹慎使用反模式設計數據庫。通常狀況下,儘量使用範式化的數據庫設計,由於範式化的數據庫設計能讓產品更加靈活,而且能在數據庫層保持數據完整性。
有的時候,提高性能最好的方法是在同一表中保存冗餘數據,若是能允許少許的髒數據,建立一張徹底獨立的彙總表或緩存表是很是好的方法。舉個例子,設計一張「下載次數表」來緩存下載次數信息,可以使在海量數據的狀況下,提升查詢總數信息的速度。
另一個比較典型的場景,出於擴展性考慮,可能會使用 BLOB 和 TEXT 類型的列存儲 JSON 結構的數據,這樣的好處在於能夠在任什麼時候候,將新的屬性添加到這個字段中,而不須要更改表結構。可是,這個設計的缺點也比較明顯,就是須要獲取整個字段內容進行解碼來獲取指定的屬性,而且沒法進行索引、排序、聚合等操做。所以,若是須要考慮更加複雜的使用場景,更加建議使用 MongoDB 這樣的文檔型數據庫。