數(shù)據(jù)庫的設(shè)計與調(diào)優(yōu)
主鍵策略
先說結(jié)果,項目最后采用了BIGINT類型的自增Id方式。
-
思路:
考慮到對事務(wù)的支持和主鍵索引效率(聚集索引),采用默認(rèn)的InnoDB引擎。在InnoDB下嗽桩,主鍵選用有以下幾個原則:
-
主鍵最好是單調(diào)(遞增)的。
因為主鍵默認(rèn)是聚集索引凄敢,而聚集索引的葉子節(jié)點存放的就是數(shù)據(jù)本身(而非地址)碌冶,索引的鍵值邏輯順序決定了表數(shù)據(jù)行的物理存儲順序,也就是說涝缝,如果索引是遞增的扑庞,則該索引在磁盤上的物理存儲地址是也相鄰的。我們都知道索引是存在磁盤而非內(nèi)存中的拒逮,磁盤有一個預(yù)讀機(jī)制罐氨,當(dāng)一個數(shù)據(jù)被讀到時,磁盤也會從這個位置開始滩援,順序向后讀取一定長度的數(shù)據(jù)放入內(nèi)存栅隐,從而減少磁盤IO,而聚集索引的設(shè)計就恰恰利用了這一點,利用更少的磁盤IO讀取更多的數(shù)據(jù)租悄。假設(shè)我們用非單調(diào)的字段作為主鍵谨究,當(dāng)我們要進(jìn)行范圍查詢(between、<恰矩、<=记盒、>憎蛤、>=)時外傅,磁盤要不停的尋址,效率大大下降俩檬;另外在插入新記錄時萎胰,數(shù)據(jù)文件為了維持B+Tree的特性會頻繁的分裂調(diào)整,十分低效棚辽。
-
主鍵不宜過長技竟。
接上一點,聚集索引使得按主鍵檢索十分高效屈藐,但是按輔助索引檢索就需要先檢索輔助索引獲得主鍵榔组,然后用主鍵到主索引中檢索獲得記錄,因此所有輔助索引都引用主索引联逻,過長的主索引會令輔助索引變得過大搓扯。PS:每個非聚簇索引都是二級索引,又叫輔助索引(secondary indexes)
確保主鍵無意義性
主鍵不應(yīng)該與業(yè)務(wù)相關(guān)(其實個人感覺業(yè)務(wù)相關(guān)的字段也很難滿足上述兩個原則)
在前面的基礎(chǔ)上,我們來看下面幾種策略:
- UUID: 缺點:非遞增包归,過長(截取后又無法保證唯一性)锨推; 優(yōu)點:在分布式環(huán)境下能保證唯一性
- 自增主鍵: 缺點:1.分布式下數(shù)據(jù)庫一般會分庫,主鍵可能會重復(fù) 2.把一個自增列的表復(fù)制到另外的表自增列會重新開始 3.主鍵是可預(yù)測的(沒有遇到過具體的問題公壤,不清楚)换可; 優(yōu)點:遞增且長度可控,實現(xiàn)簡單厦幅。
- SnowFlake:推特提出的一種分布式自增ID算法沾鳄。https://segmentfault.com/a/1190000011282426
考慮到當(dāng)前項目沒有分布式的需求,所以采用了相對簡單的自增主鍵策略确憨。
-
外鍵約束
外鍵是不可能加的译荞,這輩子都不可能加的,影響性能不說缚态,對個人開發(fā)的項目而言外鍵反而會帶來麻煩磁椒。(希望能有高手指點一下外鍵的取舍)
索引策略
- 對于性別,狀態(tài)等取值情況比較少玫芦,重復(fù)值比較多的字段浆熔,不需要加索引。索引是需要IO開銷的,假設(shè)你從100w條數(shù)據(jù)中取出50w條數(shù)據(jù)医增,那你相對需要訪問50萬次索引慎皱,再訪問50萬次表,優(yōu)化器認(rèn)為此索引使用的成本過高叶骨,不會使用索引茫多。
- 復(fù)合索引:復(fù)合索引有一個規(guī)則,從左到右使用索引中的字段忽刽,如(a,b,c)三個字段建立索引天揖,(b,c)作為條件查詢是不走索引的。
- 盡量選擇區(qū)分度高的列作為索引,區(qū)分度的公式是count(distinct col)/count(*)跪帝,比如我們不應(yīng)給性別這種字段加索引今膊。
- 更多索引優(yōu)化可以參考美團(tuán)開源的SQLAdvisor。
B+Tree詳解
可以參考美團(tuán)的技術(shù)博客伞剑,這里面講的非常透徹斑唬。