MySql分區(qū)、分表和分庫(kù) 知識(shí)掃盲 !
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
數(shù)據(jù)庫(kù)的數(shù)據(jù)量達(dá)到一定程度之后,為避免帶來(lái)系統(tǒng)性能上的瓶頸。需要進(jìn)行數(shù)據(jù)的處理,采用的手段是分區(qū)、分片、分庫(kù)、分表。
一些問(wèn)題的解釋?zhuān)?/span>
1.為什么要分表和分區(qū)?
日常開(kāi)發(fā)中我們經(jīng)常會(huì)遇到大表的情況,所謂的大表是指存儲(chǔ)了百萬(wàn)級(jí)乃至千萬(wàn)級(jí)條記錄的表。
這樣的表過(guò)于龐大,導(dǎo)致數(shù)據(jù)庫(kù)在查詢和插入的時(shí)候耗時(shí)太長(zhǎng),性能低下,
如果涉及聯(lián)合查詢的情況,性能會(huì)更加糟糕。
分表和表分區(qū)的目的就是減少數(shù)據(jù)庫(kù)的負(fù)擔(dān),提高數(shù)據(jù)庫(kù)的效率,通常點(diǎn)來(lái)講就是提高表的增刪改查效率。
2.什么是分表?
分表是將一個(gè)大表按照一定的規(guī)則分解成多張具有獨(dú)立存儲(chǔ)空間的實(shí)體表,
我們可以稱(chēng)為子表,每個(gè)表都對(duì)應(yīng)三個(gè)文件,MYD數(shù)據(jù)文件,.MYI索引文件,.frm表結(jié)構(gòu)文件。
這些子表可以分布在同一塊磁盤(pán)上,也可以在不同的機(jī)器上。
app讀寫(xiě)的時(shí)候根據(jù)事先定義好的規(guī)則得到對(duì)應(yīng)的子表名,然后去操作它。
3.什么是分區(qū)?
分區(qū)和分表相似,都是按照規(guī)則分解表。
不同在于分表將大表分解為若干個(gè)獨(dú)立的實(shí)體表,而分區(qū)是將數(shù)據(jù)分段劃分在多個(gè)位置存放,
可以是同一塊磁盤(pán)也可以在不同的機(jī)器。
分區(qū)后,表面上還是一張表,但數(shù)據(jù)散列到多個(gè)位置了。
app讀寫(xiě)的時(shí)候操作的還是大表名字,db自動(dòng)去組織分區(qū)的數(shù)據(jù)。
4.mysql分表和分區(qū)有什么聯(lián)系呢?
(1)都能提高mysql的性高,在高并發(fā)狀態(tài)下都有一個(gè)良好的表現(xiàn)。
(2)分表和分區(qū)不矛盾,可以相互配合的,對(duì)于那些大訪問(wèn)量,并且表數(shù)據(jù)比較多的表,
我們可以采取分表和分區(qū)結(jié)合的方式,訪問(wèn)量不大,但是表數(shù)據(jù)很多的表,我們可以采取分區(qū)的方式等。
(3)分表技術(shù)是比較麻煩的,需要手動(dòng)去創(chuàng)建子表,app服務(wù)端讀寫(xiě)時(shí)候需要計(jì)算子表名。
采用merge好一些,但也要?jiǎng)?chuàng)建子表和配置子表間的union關(guān)系。
(4)表分區(qū)相對(duì)于分表,操作方便,不需要?jiǎng)?chuàng)建子表。分區(qū)
MySQL的物理數(shù)據(jù),存儲(chǔ)在表空間文件(.ibdata1和.ibd)中,這里講的分區(qū)的意思是指將同一表中不同行的記錄分配到不同的物理文件中,幾個(gè)分區(qū)就有幾個(gè).idb文件。
MySQL在5.1時(shí)添加了對(duì)水平分區(qū)的支持。
分區(qū)是將一個(gè)表或索引分解成多個(gè)更小,更可管理的部分。
每個(gè)區(qū)都是獨(dú)立的,可以獨(dú)立處理,也可以作為一個(gè)更大對(duì)象的一部分進(jìn)行處理。這個(gè)是MySQL支持的功能,業(yè)務(wù)代碼無(wú)需改動(dòng)。
可以通過(guò)使用SHOW VARIABLES命令來(lái)確定MySQL是否支持分區(qū)。
MySQL分區(qū)類(lèi)型
RANGE分區(qū):基于一個(gè)給定區(qū)間邊界,得到若干個(gè)連續(xù)區(qū)間范圍,按照分區(qū)鍵的落點(diǎn),把數(shù)據(jù)分配到不同的分區(qū);
LIST分區(qū):類(lèi)似RANGE分區(qū),區(qū)別在于LIST分區(qū)是基于枚舉出的值列表分區(qū),RANGE是基于給定連續(xù)區(qū)間范圍分區(qū);
HASH分區(qū):基于用戶自定義的表達(dá)式的返回值,對(duì)其根據(jù)分區(qū)數(shù)來(lái)取模,從而進(jìn)行記錄在分區(qū)間的分配的模式。這個(gè)用戶自定義的表達(dá)式,就是MySQL希望用戶填入的哈希函數(shù)。
KEY分區(qū):類(lèi)似于按HASH分區(qū),區(qū)別在于KEY分區(qū)只支持計(jì)算一列或多列,且使用MySQL 服務(wù)器提供的自身的哈希函數(shù)。
RANGE分區(qū)
把連續(xù)區(qū)間按范圍劃分,是實(shí)戰(zhàn)最常用的一種分區(qū)類(lèi)型,行數(shù)據(jù)基于屬于一個(gè)給定的連續(xù)區(qū)間的列值被放入分區(qū)。
但是記住,當(dāng)插入的數(shù)據(jù)不在一個(gè)分區(qū)中定義的值的時(shí)候,會(huì)拋異常。
RANGE分區(qū)主要用于日期列的分區(qū),比如交易表啊,銷(xiāo)售表啊等??梢愿鶕?jù)年月來(lái)存放數(shù)據(jù)。
如果你分區(qū)走的唯一索引中date類(lèi)型的數(shù)據(jù),
那么注意了,優(yōu)化器只能對(duì)YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()這類(lèi)函數(shù)進(jìn)行優(yōu)化選擇。
實(shí)戰(zhàn)中可以用int類(lèi)型的字段來(lái)存時(shí)間戳做分區(qū)列,那么只用存yyyyMM就好了,也不用關(guān)心函數(shù)了。
CREATE TABLE
`Order` (
`id`
INT NOT NULL AUTO_INCREMENT,
`partition_key`
INT NOT NULL,
`amt`
DECIMAL(5) NULL) PARTITION BY RANGE(partition_key)
PARTITIONS 5(
PARTITION part0 VALUES LESS THAN(201901),
PARTITION part1 VALUES LESS THAN(201902),
PARTITION part2 VALUES LESS THAN(201903),
PARTITION part3 VALUES LESS THAN(201904),
PARTITION part4 VALUES LESS THAN(201905),
PARTITION part4 VALUES LESS THAN MAXVALUE;
INSERT INTO `Order` (`id`, `partition_key`, `amt`) VALUES ('1', '201901', '1000');
INSERT INTO `Order` (`id`, `partition_key`, `amt`) VALUES ('2', '201902', '800');
INSERT INTO `Order` (`id`, `partition_key`, `amt`) VALUES ('3', '201903', '1200');RANGE分區(qū)通過(guò)使用PARTITION BY RANGE(expr)實(shí)現(xiàn) , 其中“expr” 可以是某個(gè)列值, 或一個(gè)基于某個(gè)列值并返回一個(gè)整數(shù)值的表達(dá)式,如YEAR(date)。
不過(guò)值得注意的是,expr的返回值,不可以為NULL。
VALUES LESS THAN的排列必須從小到大順序列出,這樣MySQL才能識(shí)別一個(gè)一個(gè)的區(qū)間段。
涉及聚合函數(shù)SUM()、COUNT()的查詢時(shí),如果不指定分區(qū),那么會(huì)在每個(gè)分區(qū)上并行處理。
LIST分區(qū)
MySQL中的LIST分區(qū)在很多方面類(lèi)似于RANGE分區(qū)。
和RANGE分區(qū)一樣,LIST分區(qū)的每個(gè)分區(qū)必須明確定義。
它們的主要區(qū)別在于,LIST分區(qū)是基于枚舉出的值列表分區(qū),RANGE是基于給定連續(xù)區(qū)間范圍分區(qū);
LIST分區(qū)通過(guò)使用PARTITION BY LIST(expr)來(lái)實(shí)現(xiàn) 。
例如:
create table user(
a int(11),
b int(11)
)
partition by list(b)(
partition p0 values in (1,3,5,7,9),
partition p1 values in (2,4,6,8,0)
);如果試圖插入字段值(或分區(qū)表達(dá)式的返回值)不在分區(qū)值列表中的任何一行時(shí),那么“INSERT”查詢將失敗并報(bào)錯(cuò)。
要重點(diǎn)注意的是,LIST分區(qū)沒(méi)有類(lèi)似如“VALUES LESS THAN MAXVALUE”這樣的包含其他值在內(nèi)的定義。所以將要匹配的任何值都必須在值列表中能夠找到。
HASH分區(qū)
HASH分區(qū)主要用來(lái)確保數(shù)據(jù)在預(yù)先確定數(shù)目的分區(qū)中平均分布。
在RANGE和LIST分區(qū)中,我們必須明確指定一個(gè)給定的區(qū)間或列值集合,來(lái)指定哪些記錄進(jìn)入哪些分區(qū);
而在HASH分區(qū)中,MySQL自動(dòng)完成分配記錄到區(qū)間的工作,你所要做的只是確定一個(gè)用來(lái)做哈希的字段或者表達(dá)式,以及指定被分區(qū)的表將要被分割成的分區(qū)數(shù)量。
PARTITION BY HASH
例如:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;如果沒(méi)有包括一個(gè)PARTITIONS子句,那么分區(qū)的數(shù)量將默認(rèn)為1。
最有效率的哈希函數(shù)是只對(duì)單個(gè)表列進(jìn)行計(jì)算,并且它的結(jié)果值隨字段值進(jìn)行一致地增大或減小,因?yàn)檫@考慮了在分區(qū)范圍上的“修剪”。
也就是說(shuō),表達(dá)式值和它所基于的列的值變化越接近,MySQL就可以越有效地使用該表達(dá)式來(lái)進(jìn)行HASH分區(qū)。
當(dāng)使用了“PARTITION BY HASH”時(shí),MySQL將基于用戶提供的函數(shù)結(jié)果的模數(shù)來(lái)確定使用哪個(gè)編號(hào)的分區(qū)。換句話,對(duì)于一個(gè)表達(dá)式“expr”,將要保存記錄的分區(qū)編號(hào)為N ,其中“N = MOD(expr, num)”。
KEY分區(qū)
按照KEY進(jìn)行分區(qū)類(lèi)似于按照HASH分區(qū),除了HASH分區(qū)使用的用戶定義的表達(dá)式,而KEY分區(qū)的哈希函數(shù)是由MySQL 服務(wù)器提供。
MySQLCluster使用函數(shù)MD5()來(lái)實(shí)現(xiàn)KEY分區(qū);對(duì)于使用其他存儲(chǔ)引擎的表,服務(wù)器使用其自己內(nèi)部的 哈希函數(shù),這些函數(shù)是基于與PASSWORD()一樣的運(yùn)算法則。
“CREATE TABLE ... PARTITION BY KEY”的語(yǔ)法規(guī)則類(lèi)似于創(chuàng)建一個(gè)通過(guò)HASH分區(qū)的表的規(guī)則。它們唯一的區(qū)別在于使用的關(guān)鍵字是KEY而不是HASH,并且KEY分區(qū)只采用一個(gè)或多個(gè)列名的一個(gè)列表。
create table user(
a int(11),
b datetime
)
partition by key(b)
partitions 4;
子分區(qū)
子分區(qū)是分區(qū)表中每個(gè)分區(qū)的再次分割。
例如:
CREATE TABLE ts (id INT, purchased DATE)
PARTITION BY RANGE(YEAR(purchased))
SUBPARTITION BY HASH(TO_DAYS(purchased))
(
PARTITION p0 VALUES LESS THAN (1990)
(
SUBPARTITION s0,
SUBPARTITION s1
),
PARTITION p1 VALUES LESS THAN (2000)
(
SUBPARTITION s2,
SUBPARTITION s3
),
PARTITION p2 VALUES LESS THAN MAXVALUE
(
SUBPARTITION s4,
SUBPARTITION s5
)
);
注意的語(yǔ)法項(xiàng):
每個(gè)分區(qū)必須有相同數(shù)量的子分區(qū)。
如果在一個(gè)分區(qū)表上的某個(gè)分區(qū)上使用SUBPARTITION來(lái)明確定義子分區(qū),那么就必須定義其他所有分區(qū)的子分區(qū)。
子分區(qū)可以用于特別大的表,在多個(gè)磁盤(pán)間分配數(shù)據(jù)和索引。
然后就可以根據(jù)具體的情況來(lái)持久化:
CREATE TABLE ts (id INT, purchased DATE)
PARTITION BY RANGE(YEAR(purchased))
SUBPARTITION BY HASH(TO_DAYS(purchased))
(
PARTITION p0 VALUES LESS THAN (1990)
(
SUBPARTITION s0a
DATA DIRECTORY = '/disk0'
INDEX DIRECTORY = '/disk1',
SUBPARTITION s0b
DATA DIRECTORY = '/disk2'
INDEX DIRECTORY = '/disk3'
),
PARTITION p1 VALUES LESS THAN (2000)
(
SUBPARTITION s1a
DATA DIRECTORY = '/disk4/data'
INDEX DIRECTORY = '/disk4/idx',
SUBPARTITION s1b
DATA DIRECTORY = '/disk5/data'
INDEX DIRECTORY = '/disk5/idx'
),
PARTITION p2 VALUES LESS THAN MAXVALUE
(
SUBPARTITION s2a,
SUBPARTITION s2b
)
);
DATA DIRECTORY表示數(shù)據(jù)的物理文件的存放目錄
INDEX DIRECTORY表示索引的物理文件的存放目錄
分區(qū)的管理
MySQL提供了許多修改分區(qū)表的方式。添加、刪除、重新定義、合并或拆分已經(jīng)存在的分區(qū)是可能的。
所有這些操作都可以通過(guò)使用ALTER TABLE命令的分區(qū)擴(kuò)展來(lái)實(shí)現(xiàn)。
新增分區(qū)
為已創(chuàng)建的未分區(qū)表創(chuàng)建分區(qū):
RANGE:
ALTER TABLE tb PARTITION BY RANGE (expr) ( range_partitions_exprs(n>0) );LIST:
ALTER TABLE tb PARTITION BY LIST (expr) ( list_partitions_exprs(n>0) );HASH:
ALTER TABLE tb PARTITION BY HASH(expr) PARTITIONS 2;KEY:
ALTER TABLE tb PARTITION BY KEY(expr) PARTITIONS 2;
為分區(qū)表添加n個(gè)分區(qū):
RANGE:
ALTER TABLE tb ADD PARTITION ( range_partitions_exprs(n>0) );LIST:
ALTER TABLE tb ADD PARTITION ( list_partitions_exprs(n>0) );HASH & KEY:
ALTER TABLE tb ADD PARTITION PARTITIONS n;
調(diào)整分區(qū)
reorganize
數(shù)據(jù)不丟失的前提下,將m個(gè)分區(qū)合并為n個(gè)分區(qū)(m>n),即減量重新組織分區(qū)
RANGE:
ALTER TABLE tb REORGANIZE PARTITION s0,s1,... INTO ( range_partitions_exprs(n) )LIST:
ALTER TABLE tb REORGANIZE PARTITION s0,s1,... INTO ( list_partitions_exprs(n) )HASH & KEY:
ALTER TABLE clients COALESCE PARTITION n; (n小于原有分區(qū)數(shù))
數(shù)據(jù)不丟失的前提下,將分區(qū)表的m個(gè)分區(qū)拆分為n個(gè)分區(qū)(m<n),即增量重新組織分區(qū)
RANGE:
ALTER TABLE tb REORGANIZE PARTITION p0,p1,... INTO ( range_partitions_exprs(n) )LIST:
ALTER TABLE tb REORGANIZE PARTITION p0,p1,... INTO ( list_partitions_exprs(n) )
不能使用REORGANIZE PARTITION來(lái)改變表的分區(qū)類(lèi)型;也就是說(shuō)。
重建分區(qū),即先刪除分區(qū)中的所有記錄,然后重新插入??捎糜谡矸謪^(qū)碎片。
ALTER TABLE tb REBUILD PARTITION p0, p1;
優(yōu)化分區(qū),整理分區(qū)碎片 optimize
ALTER TABLE tb OPTIMIZE PARTITION p0, p1;
如從分區(qū)中刪除了大量的行,或者對(duì)一個(gè)帶有可變長(zhǎng)度字段(VARCHAR、BLOB、TEXT類(lèi)型)的行作了許多修改,可以使用優(yōu)化分區(qū)來(lái)收回沒(méi)有使用的空間,并整理分區(qū)數(shù)據(jù)文件的碎片。
修復(fù)分區(qū),修補(bǔ)被破壞的分區(qū)。
ALTER TABLE tb REPAIR PARTITION p0,p1;
檢查分區(qū),這個(gè)命令可以告訴你分區(qū)中的數(shù)據(jù)或索引是否已經(jīng)被破壞,如果被破壞,請(qǐng)使用修復(fù)分區(qū)來(lái)修補(bǔ)
ALTER TABLE tb CHECK PARTITION p1;
刪除分區(qū)
刪除一個(gè)分區(qū),以及分區(qū)內(nèi)的所有數(shù)據(jù):
ALTER TABLE tb DROP PARTITION p2;
刪除一個(gè)分區(qū),但保留分區(qū)內(nèi)的所有數(shù)據(jù)(MySQL 5.5引入):truncate
ALTER TABLE tb TRUNCATE PARTITION p2;
查看分區(qū)
查看某個(gè)schema下某個(gè)表的分區(qū)信息
SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA = 'xxx' AND TABLE_NAME LIKE 'xxxx';
分析某個(gè)分區(qū),主要看行數(shù)和名稱(chēng)以及狀態(tài)
ALTER TABLE tb ANALYZE PARTITION p3;
分表
分表顧名思義,就是把一張超大的數(shù)據(jù)表,拆分為多個(gè)較小的表,得到有效的緩解。
超大表會(huì)帶來(lái)如下的影響:
單表數(shù)據(jù)量太大,會(huì)被頻繁讀寫(xiě),加鎖操作密集,導(dǎo)致性能降低。
單表數(shù)據(jù)量太大,對(duì)應(yīng)的索引也會(huì)很大,查詢效率降低,增刪操作的性能也會(huì)降低。
分表和分區(qū)看起來(lái)十分類(lèi)似,確實(shí),分區(qū)已經(jīng)能夠在磁盤(pán)層面將一張表拆分成多個(gè)文件了,理論上前面提到的大表的問(wèn)題都能得到有效解決。因?yàn)?strong>分區(qū)就是分表的數(shù)據(jù)庫(kù)實(shí)現(xiàn)版本。
在MySQL 5.1分區(qū)功能出現(xiàn)以前,要想解決超大表問(wèn)題,只能采用分表操作,因?yàn)檫@類(lèi)問(wèn)題十分常見(jiàn),MySQL才自帶了一個(gè)分區(qū)功能,以達(dá)到相同的效果。
所以你可以直接說(shuō)分區(qū)就是分表的替代,分表是分區(qū)出現(xiàn)以前的做法。不過(guò)這不代表我們就沒(méi)有必要學(xué)習(xí)分表了,相反,水平分表的功能或許可以用更加便捷的分區(qū)來(lái)替代,但是垂直分表的功能,分區(qū)卻無(wú)法替代。
分表只能通過(guò)程序代碼來(lái)實(shí)現(xiàn),目前市面上有許多分表的框架。( Apache ShardingSphere )
分表和分區(qū)的區(qū)別
分區(qū)只是一張表中的數(shù)據(jù)和索引的存儲(chǔ)位置發(fā)生改變,分表則是將一張表分成多張表,是真實(shí)的有多套表的配套文件
分區(qū)沒(méi)法突破數(shù)據(jù)庫(kù)層面,不論怎么分區(qū),這些分區(qū)都要在一個(gè)數(shù)據(jù)庫(kù)下。而分表可以將子表分配在同一個(gè)庫(kù)中,也可以分配在不同庫(kù)中,突破數(shù)據(jù)庫(kù)性能的限制。
分區(qū)只能替代水平分表的功能,無(wú)法取代垂直分表的功能。
分表的類(lèi)型
分表分為水平分表和垂直分表。
水平分表
水平分表和分區(qū)很像,或者說(shuō)分區(qū)就是水平分表的數(shù)據(jù)庫(kù)實(shí)現(xiàn)版本,它們分的都是行記錄。

但是需要注意,如果這些表還是在同一個(gè)庫(kù)中,所以庫(kù)級(jí)別的數(shù)據(jù)庫(kù)操作還是有IO瓶頸。分表可以將單張表的數(shù)據(jù)切分到多個(gè)服務(wù)器上去,每個(gè)服務(wù)器具有相應(yīng)的庫(kù)與子表,這是分區(qū)所不能有的優(yōu)勢(shì)。
水平分表的切分規(guī)則一般有如下幾種:
范圍切分
可以根據(jù)某個(gè)字段的范圍做劃分,比如訂單號(hào)字段,從0到10000一個(gè)表,10001到20000一個(gè)表。
HASH取模
可以根據(jù)某個(gè)字段的HASH取模做劃分,比如將一個(gè)用戶表分成10個(gè)子表,可以取用戶id,然后hash后取10的模,從而分配到不同的數(shù)據(jù)庫(kù)上。不過(guò)這種劃分一旦確定后,就無(wú)法改變子表數(shù)量了。
地理/國(guó)籍/類(lèi)型等
比如按照華東,華南,華北這樣來(lái)區(qū)分業(yè)務(wù)表,或者安卓用戶,IOS用戶等來(lái)區(qū)分用戶表。
時(shí)間
按照時(shí)間切分,比如將6個(gè)月前,甚至一年前的數(shù)據(jù)切出去放到另外的一張表,因?yàn)殡S著時(shí)間流逝,這些表的數(shù)據(jù)被查詢的概率變小,所以沒(méi)必要和“熱數(shù)據(jù)”放在一起,這個(gè)也是“冷熱數(shù)據(jù)分離”。
垂直分表
水平分表分的是行記錄,而垂直分表,分的是列字段,它就像用一把刀,垂直的將一個(gè)表切成多張表一樣。
垂直分表是基于列字段進(jìn)行的。一般是表中的字段較多,或者有數(shù)據(jù)較大長(zhǎng)度較長(zhǎng)(比如text,blob,varchar(1000)以上的字段)的字段時(shí),我們將不常用的,或者數(shù)據(jù)量大的字段拆分到“擴(kuò)展表”上。這樣避免查詢時(shí),數(shù)據(jù)量太大造成的“跨頁(yè)”問(wèn)題。
垂直分表的切分規(guī)則很好理解,一般是“不常用”或者“字段數(shù)據(jù)量大”這兩點(diǎn)來(lái)做切割

分庫(kù)
分庫(kù)同樣是為了應(yīng)對(duì)超大數(shù)據(jù)帶來(lái)的巨大的IO需求,如果不拆庫(kù),那么單庫(kù)所能支持的吞吐能力和磁盤(pán)空間,就會(huì)成為制衡業(yè)務(wù)發(fā)展的瓶頸。
分庫(kù)的主要目的是為突破單節(jié)點(diǎn)數(shù)據(jù)庫(kù)服務(wù)器的I/O能力限制,解決數(shù)據(jù)庫(kù)水平擴(kuò)展性問(wèn)題。
分庫(kù)作用
分區(qū)和分表可以把單表分到不同的硬盤(pán)上,但不能分配到不同服務(wù)器上。一臺(tái)機(jī)器的性能是有限制的,用分庫(kù)可以解決單臺(tái)服務(wù)器性能不夠,或者成本過(guò)高問(wèn)題。
將一個(gè)庫(kù)分成多個(gè)庫(kù),并在多個(gè)服務(wù)器上部署,就可以突破單服務(wù)器的性能瓶頸,這是分庫(kù)必要性的最主要原因。
分庫(kù)的類(lèi)型
分庫(kù)同樣分為水平分庫(kù)和垂直分庫(kù)。
水平分庫(kù)
水平分庫(kù)和水平分表相似,并且關(guān)系緊密,水平分庫(kù)就是將單個(gè)庫(kù)中的表作水平分表,然后將子表分別置于不同的子庫(kù)當(dāng)中,獨(dú)立部署。
因?yàn)閹?kù)中內(nèi)容的主要載體是表,所以水平分庫(kù)和水平分表基本上如影隨形。
例如用戶表,我們可以使用注冊(cè)時(shí)間的范圍來(lái)分表,將2020年注冊(cè)的用戶表usrtb2020部署在usrdata20中,2021年注冊(cè)的用戶表usrtb2021部署在usrdata21中。
垂直分庫(kù)
同樣的,垂直分庫(kù)和垂直分表也十分類(lèi)似,不過(guò)垂直分表拆分的是字段,而垂直分庫(kù),拆分的是表。
垂直分庫(kù)是將一個(gè)庫(kù)下的表作不同維度的分類(lèi),然后將其分配給不同子庫(kù)的策略。
例如,我們可以將用戶相關(guān)的表都放置在usrdata這個(gè)庫(kù)中,將訂單相關(guān)的表都放置在odrdata中,以此類(lèi)推。
垂直分庫(kù)的分類(lèi)維度有很多,可以按照業(yè)務(wù)模塊劃分(用戶/訂單...),按照技術(shù)模塊分(日志類(lèi)庫(kù)/圖片類(lèi)庫(kù)...),或者空間,時(shí)間等等。

問(wèn)題
事務(wù)問(wèn)題。
問(wèn)題描述:在執(zhí)行分庫(kù)分表之后,由于數(shù)據(jù)存儲(chǔ)到了不同的庫(kù)上,數(shù)據(jù)庫(kù)事務(wù)管理出現(xiàn)了困難。如果依賴(lài)數(shù)據(jù)庫(kù)本身的分布式事務(wù)管理功能去執(zhí)行事務(wù),將付出高昂的性能代價(jià);如果由應(yīng)用程序去協(xié)助控制,形成程序邏輯上的事務(wù),又會(huì)造成編程方面的負(fù)擔(dān)。
解決方法:利用分布式事務(wù),協(xié)調(diào)不同庫(kù)之間的數(shù)據(jù)原子性,一致性。
跨庫(kù)跨表的join問(wèn)題。
問(wèn)題描述:在執(zhí)行了分庫(kù)分表之后,難以避免會(huì)將原本邏輯關(guān)聯(lián)性很強(qiáng)的數(shù)據(jù)劃分到不同的表、不同的庫(kù)上,這時(shí),表的關(guān)聯(lián)操作將受到限制,我們無(wú)法join位于不同分庫(kù)的表,也無(wú)法join分表粒度不同的表,結(jié)果原本一次查詢能夠完成的業(yè)務(wù),可能需要多次查詢才能完成。
解決方法:tddl、MyCAT等都支持跨分片join。但是我們應(yīng)該盡力避免跨庫(kù)join,如果一定要整合數(shù)據(jù),那么請(qǐng)?jiān)诖a中多次查詢完成。
額外的數(shù)據(jù)管理負(fù)擔(dān)和數(shù)據(jù)運(yùn)算壓力。
問(wèn)題描述:額外的數(shù)據(jù)管理負(fù)擔(dān),最顯而易見(jiàn)的就是數(shù)據(jù)的定位問(wèn)題和數(shù)據(jù)的增刪改查的重復(fù)執(zhí)行問(wèn)題,這些都可以通過(guò)應(yīng)用程序解決,但必然引起額外的邏輯運(yùn)算,例如,對(duì)于一個(gè)記錄用戶成績(jī)的用戶數(shù)據(jù)表userTable,業(yè)務(wù)要求查出成績(jī)最好的100位,在進(jìn)行分表之前,只需一個(gè)order by語(yǔ)句就可以搞定,但是在進(jìn)行分表之后,將需要n個(gè)order by語(yǔ)句,分別查出每一個(gè)分表的前100名用戶數(shù)據(jù),然后再對(duì)這些數(shù)據(jù)進(jìn)行合并計(jì)算,才能得出結(jié)果。
解決方法:無(wú)解,這是水平拓展的代價(jià)。
作者 | ML李嘉圖
來(lái)源 | cnblogs.com/zwtblog/p/15332735.html

加鋒哥微信: java3459 圍觀鋒哥朋友圈,每天推送Java干貨!
