一分鐘掌握數(shù)據(jù)庫垂直拆分

2018-09-06 17:11 更新

一、緣起

當(dāng)數(shù)據(jù)庫的數(shù)據(jù)量非常大時,水平切分垂直拆分是兩種常見的降低數(shù)據(jù)庫大小,提升性能的方法。假設(shè)有用戶表:

user(
uid bigint,
name varchar(16),
pass varchar(16),
age int,
sex tinyint,
flag tinyint,
sign varchar(64),
intro varchar(256)

…);

水平切分是指,以某個字段為依據(jù)(例如uid),按照一定規(guī)則(例如取模),將一個庫(表)上的數(shù)據(jù)拆分到多個庫(表)上,以降低單庫(表)大小,達(dá)到提升性能的目的的方法,水平切分后,各個庫(表)的特點是:

(1)每個庫(表)的結(jié)構(gòu)都一樣

(2)每個庫(表)的數(shù)據(jù)都不一樣,沒有交集

(3)所有庫(表)的并集是全量數(shù)據(jù)


二、什么是垂直拆分

垂直拆分是指,將一個屬性較多,一行數(shù)據(jù)較大的表,將不同的屬性拆分到不同的表中,以降低單庫(表)大小,達(dá)到提升性能的目的的方法,垂直切分后,各個庫(表)的特點是:

(1)每個庫(表)的結(jié)構(gòu)都不一樣

(2)一般來說,每個庫(表)的屬性至少有一列交集,一般是主鍵

(3)所有庫(表)的并集是全量數(shù)據(jù)

還是以上文提到的用戶表為例,如果要垂直拆分,可能拆分結(jié)果會是這樣的:

user_base(
uid bigint,
name varchar(16),
pass varchar(16),
age int,
sex tinyint,
flag tinyint,
…);

user_ext(
uid bigint, 
sign varchar(64),
intro varchar(256)
…);

三、垂直切分的依據(jù)是什么

當(dāng)一個表屬性很多時,如何來進(jìn)行垂直拆分呢?如果沒有特殊情況,拆分依據(jù)主要有幾點:

(1)將長度較短,訪問頻率較高的屬性盡量放在一個表里,這個表暫且稱為主表

(2)將字段較長,訪問頻率較低的屬性盡量放在一個表里,這個表暫且稱為擴展表

如果1和2都滿足,還可以考慮第三點:

(3)經(jīng)常一起訪問的屬性,也可以放在一個表里

優(yōu)先考慮1和2,第3點不是必須。另,如果實在屬性過多,主表和擴展表都可以有多個。


一般來說,數(shù)據(jù)量并發(fā)量比較大時,數(shù)據(jù)庫的上層都會有一個服務(wù)層。需要注意的是,當(dāng)應(yīng)用方需要同時訪問主表和擴展表中的屬性時,服務(wù)層不要使用join來連表訪問,而應(yīng)該分兩次進(jìn)行查詢
數(shù)據(jù)庫服務(wù)層

原因是,大數(shù)據(jù)高并發(fā)互聯(lián)網(wǎng)場景下,一般來說,吞吐量和擴展性主要矛盾

(1)join更消損耗數(shù)據(jù)庫性能

(2)join會讓base表和ext表耦合在一起(必須在一個數(shù)據(jù)庫實例上),不利于數(shù)據(jù)量大時拆分到不同的數(shù)據(jù)庫實例上(機器上)。畢竟減少數(shù)據(jù)量,提升性能才是垂直拆分的初衷。


四、為什么要這么這么拆分

為何要將字段短,訪問頻率高的屬性放到一個表內(nèi)?為何這么垂直拆分可以提升性能?因為:

(1)數(shù)據(jù)庫有自己的內(nèi)存buffer,會將磁盤上的數(shù)據(jù)load到內(nèi)存buffer里(暫且理解為進(jìn)程內(nèi)緩存吧)

(2)內(nèi)存buffer緩存數(shù)據(jù)是以row為單位

(3)在內(nèi)存有限的情況下,在數(shù)據(jù)庫內(nèi)存buffer里緩存短row,就能緩存更多的數(shù)據(jù)

(4)在數(shù)據(jù)庫內(nèi)存buffer里緩存訪問頻率高的row,就能提升緩存命中率,減少磁盤的訪問


舉個例子就很好理解了:

假設(shè)數(shù)據(jù)庫內(nèi)存buffer為1G,未拆分的user表1行數(shù)據(jù)大小為1k,那么只能緩存100w行數(shù)據(jù)。

如果垂直拆分成user_base和user_ext,其中:

(1)user_base訪問頻率高(例如uid, name, passwd, 以及一些flag等),一行大小為0.1k

(2)user_ext訪問頻率低(例如簽名, 個人介紹等),一行大小為0.9k

那邊內(nèi)存buffer就就能緩存近乎1000w行user_base的記錄,訪問磁盤的概率會大大降低,數(shù)據(jù)庫訪問的時延會大大降低,吞吐量會大大增加。


五、總結(jié)

(1)水平拆分垂直拆分都是降低數(shù)據(jù)量大小,提升數(shù)據(jù)庫性能的常見手段

(2)流量大,數(shù)據(jù)量大時,數(shù)據(jù)訪問要有service層,并且service層不要通過join來獲取主表和擴展表的屬性

(3)垂直拆分的依據(jù),盡量把長度較短,訪問頻率較高的屬性放在主表


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號