我的原文:www.hijerry.cn/p/6196.html
前言
資料也是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表情。
查詢
儘量避免大SQL查詢。
儘量基於索引查詢。
比起構造一個複雜的SQL查詢做一次查詢,簡單、短小的基於索引的多次查詢效率會更高。
例項:使用者表
這張表取自我的畢業設計,先看錶結構:
上面所有的整數型別都是 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`)
複製程式碼
這主要用於區分不同型別的使用者。