Web總結:資料庫系統
前言
資料也是Web應用最重要的部分,而資料庫恰好也是Web應用最容易出瓶頸的地方。經過幾年的學習、實踐我逐漸總結出了一套自己的資料庫設計、實踐原則,有一些是參考企業的,同時自己的優化方法也在裡面。
選擇合適的資料庫
Mysql
是目前的主流資料庫之一,幾乎可以承擔起所有Web站點的資料處理操作(通過叢集、主從等優化手段)。
大型應用會使用Oracel
作為資料庫(比如銀行、證券、電信)。
另外值得一提的是NOSQL
,由於它的靈活性高於關係型資料庫,所以常用於作為快取系統,如MemCache、Redis。
目前JS全棧流派會使用MongoDB作為後臺資料庫。即便如此,我還是推薦使用關係型資料庫作為主資料庫,而NOSQL作為輔助資料庫。
一些原則
以下的設計都是基於Mysql
的。
正規化和冗餘
關係型資料庫的正規化有六種,這是理論上的。
在實際開發中,往往達到第三正規化即可,並新增一些冗餘欄位用於加快查詢速度。
主外來鍵
建立邏輯上的主外來鍵,但不建立硬性的主外來鍵關係。
邏輯上的主外來鍵意味著,主外來鍵關係的維護交於程式來完成,而不是資料庫系統。
這樣可以避免主外來鍵衝突而引起的不必要bug。
儘量不使用組合主鍵。
欄位型別和大小
在為一個欄位指定型別時,儘量使用整數型別
。因為查詢效率高,儲存空間小。
整數型別欄位,儘量使用 unsigned
。如果確實需要表示負數,那就用有符號的整數型別。
如果欄位長度已知,務必使用char
而不是varchar
。varchar
容易產生資料碎片,影響效率。比如儲存MD5雜湊值。
儘量避免可空
欄位,並給欄位設定預設值。NULL
是一個非常噁心的東西,可能會引起索引分裂,並且有時候會引起意料之外的BUG。
索引
不要隨意建立索引,應當根據慢查詢建立適當的索引。比如經常需要排序、分組的欄位,可以建立索引。
把組合主鍵、值唯一的欄位建立為唯一索引。
儘量使用資料量比較少的索引。比如在整數型別上建立,而不是在文字型別上。這也意味著,在對 text
等資料量比較大的欄位建立索引時,應取欄位的前面幾個字元建立索引即可,而不是建立全文索引。
儘量選擇取值範圍更大的欄位建立索引。比如我們不應該在 性別
儘量擴充套件索引,而不是建立一個新的。比如已有索引(user_id),現在要建立class_id的索引,可以考慮建立為(user_id, class_id)。
索引的建立是否恰當,最終取決於查詢速度是否提高了。所以建議根據慢查詢日誌來建立適當的索引。
編碼
儘量使用utf8mb4
編碼,這是四位元組的UTF-8編碼,是符合標準意義的。而utf8
編碼是用三位元組存的,所以不能儲存emoji表情。
例項:使用者表
這張表取自我的畢業設計,先看錶結構:
上面所有的整數型別都是 unsigned
型別的
id
主鍵欄位必有type
標識使用者型別。unsigned tinyint(0~255)足矣。login
登入名。必須是變長的,因為這是使用者設定的,最多不超過32
字元。telephone
手機號碼。也可以用bigint
儲存。也可以用char(11)
來存,也可以用char(13)
來存(區號2位),這裡用了varchar(24)
是考慮到不同國家長度也不一樣,乾脆用變長字元來存了。email
郵箱地址。目前最長的郵箱是32
字元,理論最長是320
字元,這裡折中取了128
字元。password
密碼。這裡是是使用Hash:make
方法生成的,最長只有60
位,所以長度是60
,並且為了避免編碼問題,使用binary
欄位來儲存。gender
性別。也可以使用enum
儲存,但強烈不推薦,更何況只是用來儲存整數形式的內容。所以直接用tinyint
型別。register_ip
、last_login_ip
。ipv4地址。32
位的ipv4地址正好可以用一個int型別儲存。php裡使用ip2long
函式即可完成轉換。如果遇到ipv6
地址,就需要用binary(16)
來存了。create_time
、update_time
、delete_time
是Laravel框架所使用的用於記錄資料時間的欄位,所以沒辦法設定為了可以為空
。
看看索引:
UNIQUE KEY `type` (`type`,`login`)
這主要用於區分不同型別的使用者。