{eval=Array;=+count(Array);}
在現(xiàn)在的互聯(lián)網(wǎng)架構(gòu)中,分庫(kù)分表是一種非常常見的手段,主要用于解決單表或者單庫(kù)數(shù)據(jù)過(guò)多而導(dǎo)致的性能問題。
垂直切分在我們的微服務(wù)架構(gòu)中很常見,將數(shù)據(jù)庫(kù)根據(jù)業(yè)務(wù)模塊進(jìn)行拆分,業(yè)務(wù)的邏輯處理都通過(guò)服務(wù)調(diào)用來(lái)進(jìn)行,而不是將邏輯放在數(shù)據(jù)層面,這樣就能降低數(shù)據(jù)庫(kù)表與表之間的耦合度。
而水平切分,就是我們通常用來(lái)解決數(shù)據(jù)問題的手段了。將數(shù)據(jù)庫(kù)中單表的數(shù)據(jù)進(jìn)行切分,分成多張相同的表單,數(shù)據(jù)按照一定的規(guī)則分布到不同的數(shù)據(jù)庫(kù)實(shí)例中,從而達(dá)到降低數(shù)據(jù)量、提高性能的目的。
使用哪個(gè)字段來(lái)作為分庫(kù)的依據(jù)呢?
通常情況下,我們會(huì)選擇主鍵作為分庫(kù)的依據(jù),根據(jù)一定的算法,將數(shù)據(jù)均勻的分布到每個(gè)數(shù)據(jù)庫(kù)實(shí)例中,同時(shí),盡量讓請(qǐng)求也均勻的分布到每個(gè)數(shù)據(jù)庫(kù)實(shí)例上。
例如:我們將訂單表進(jìn)行了切分,一分為二(DB1、BD2),訂單表的主鍵就是訂單ID,我們想要均勻的分布數(shù)據(jù)的話,我們可以對(duì)訂單ID進(jìn)行判斷,是單數(shù),我們就放在DB1中,是雙數(shù),我們就放到DB2中,這樣,我們的數(shù)據(jù)分布就非常的平均,同時(shí),我們的請(qǐng)求在概率上,也是平均的。
當(dāng)然,分庫(kù)依據(jù)可以很多,這個(gè)可以根據(jù)自己的業(yè)務(wù)場(chǎng)景進(jìn)行設(shè)置,只要明白,我們分庫(kù)是為了緩解數(shù)據(jù)庫(kù)的壓力,降低單表的數(shù)據(jù)量,如果我們分庫(kù)以后,DB1的數(shù)據(jù)量和請(qǐng)求數(shù)遠(yuǎn)大于DB2,那么我們分庫(kù)的意義就不是很大了。
通常情況下,我們的分頁(yè)查詢都是通過(guò)時(shí)間維度進(jìn)行排序的。如以下sql:
select * from T order by time offset X limit Y;
但是,分庫(kù)以后,不同的數(shù)據(jù)庫(kù)如何進(jìn)行查詢排序呢?我們就來(lái)說(shuō)一跨庫(kù)的分頁(yè)查詢方式。
假設(shè),我們現(xiàn)在要查詢某張表的第三頁(yè)數(shù)據(jù),每頁(yè)100條數(shù)據(jù),曾經(jīng)沒有分庫(kù)的時(shí)候,我們只需要
select * from T order by time offset 200 limit 100;
但是,分庫(kù)以后,這第三頁(yè)的100條數(shù)據(jù)就有很多種分布方式了。
1)均勻分布(極端情況)
數(shù)據(jù)非常均勻的分布在兩個(gè)庫(kù)中,想要找到第三頁(yè)的數(shù)據(jù),就在兩個(gè)庫(kù)中各取50%就好了。
2)全部來(lái)自一個(gè)庫(kù)(極端情況)
數(shù)據(jù)非常不平均的分配到了一個(gè)庫(kù)中,所有的數(shù)據(jù)都來(lái)至于一個(gè)庫(kù),也就是說(shuō),只需要取這個(gè)單庫(kù)的數(shù)據(jù)就可以了。
3)散亂分布(通常情況)
這種情況下,我們很難知道,第三頁(yè)的數(shù)據(jù)應(yīng)該在不同的庫(kù)中從第幾條開始取數(shù),因?yàn)榉謳?kù)后,我們丟失了全局視野。因此,如果我們想要精準(zhǔn)的找到目標(biāo)數(shù)據(jù),就必須重新構(gòu)建全局的視野。
如何重新構(gòu)建這種全局視野呢?
還是用我們要查詢第三頁(yè)的數(shù)據(jù)來(lái)舉例,我們可以將兩個(gè)庫(kù)中的第一到第三頁(yè)的數(shù)據(jù)全部查詢出來(lái),然后在內(nèi)存中合并后進(jìn)行排序,再取出第三頁(yè)的數(shù)據(jù)。
我們的sql也就發(fā)生了變化,從
select * from T order by time offset 200 limit 100;
改為
select * from T order by time offset 0 limit 100+200;
全局視野方式進(jìn)行查詢的好處很明顯,就是能夠讓業(yè)務(wù)數(shù)據(jù)絕對(duì)精準(zhǔn)的返回。但是缺點(diǎn)也是明顯,數(shù)據(jù)的查詢量大,而且消耗的內(nèi)存資源較多,當(dāng)頁(yè)碼增大的時(shí)候,性能會(huì)集聚的下降。
如果想要解決全局視野方式的缺點(diǎn),我們可以做出交互上的一點(diǎn)小犧牲來(lái)實(shí)現(xiàn)
相信這個(gè)分頁(yè)方式大家都不陌生,但是,這種分頁(yè)方式確實(shí)讓我們分庫(kù)以后的查詢難度幾何級(jí)的提升,如果想要解決跨頁(yè)查詢的問題,我們可以對(duì)我們的分頁(yè)控件進(jìn)行優(yōu)化,只保留“上一下”、“下一頁(yè)”的功能,去掉跳轉(zhuǎn)頁(yè)的功能。
當(dāng)禁止跳頁(yè)以后,我們每次查詢后,就能夠得到當(dāng)頁(yè)最后一次查詢結(jié)果的時(shí)間,我們要查詢一個(gè)分頁(yè)中的記錄時(shí),是需要查詢大于當(dāng)前時(shí)間的100條記錄就可以了。
兩個(gè)數(shù)據(jù)庫(kù)中各取100條,然后再匯總排序,這樣就能夠大大的提升查詢的效率,同時(shí)也保證了數(shù)據(jù)的精準(zhǔn)。
我們的sql也就改成了
select * from T order by time where time>@preMaxTime limit 100;
使用此方式,我們就不會(huì)因?yàn)轫?yè)碼增加而出現(xiàn)性能的下降了,只是用戶的交互體驗(yàn)會(huì)稍差一些了。當(dāng)然,如果是APP用戶,就不用擔(dān)心這點(diǎn)了,因?yàn)锳PP用戶很少使用跳轉(zhuǎn)頁(yè)的交互方式。
允許精度損失的方式就比較暴力,我們不去管數(shù)據(jù)的分布問題,只是單純的每個(gè)庫(kù)中取出50條數(shù)據(jù),然后排序展示。
在業(yè)務(wù)中,可能會(huì)出現(xiàn)第二頁(yè)的部分?jǐn)?shù)據(jù)時(shí)間上早于第一頁(yè)的數(shù)據(jù),這主要還是根據(jù)我們的保存數(shù)據(jù)時(shí)候分分布情況來(lái)決定。如果我們存儲(chǔ)數(shù)據(jù)的時(shí)候,分布得越平均,這種查詢方式得到的結(jié)果自然就越精準(zhǔn)。
使用這種方式,我們就不需要考慮性能上的問題,也不需要考慮頁(yè)面跳轉(zhuǎn)和頁(yè)碼的問題,查詢的復(fù)雜度是最低的,是比較推薦的一種查詢方式。
當(dāng)然,如果你的業(yè)務(wù)不允許這樣的情況出現(xiàn),還需要滿足交互、效率等等各種需求,那么,就只有使用最后一個(gè)方式了。
這可以說(shuō)是解決分庫(kù)查詢的究極武器了,能夠保證數(shù)據(jù)的精準(zhǔn)度、查詢的效率、用戶的交互頁(yè)面,犧牲的只是小小的性能開銷和一些代碼難度的上升。
方式其實(shí)也不難,假設(shè)我們要查詢第21頁(yè)的數(shù)據(jù),每頁(yè)5條。這個(gè)時(shí)候,我們先假設(shè)數(shù)據(jù)是平均分布的,但是我們?cè)诿總€(gè)庫(kù)都查詢?nèi)康?條數(shù)據(jù)。也就是:
select * from T order by time offset 100 limit 5;
這時(shí),我們得到的數(shù)據(jù)可能是這樣的。
而兩個(gè)DB中,最小的時(shí)間是1487500001【minTime】,這個(gè)時(shí)間記錄下來(lái)。兩個(gè)DB中各自的最大時(shí)間也記錄下來(lái),分別是DB1:1487500041【maxTime1】 和 DB2:1487500061【maxTime2】。
這時(shí),我們?cè)谑褂脮r(shí)間去兩個(gè)數(shù)據(jù)庫(kù)中再次進(jìn)行查詢。
select * from T where time between minTime and maxTime1 order by time;
select * from T where time between minTime and maxTime2 order by time;
由于之前minTime來(lái)自于DB1,因此,DB1的數(shù)據(jù)不會(huì)發(fā)生變化,但是DB2中的條件被放寬了,因此可能會(huì)查詢出更多的數(shù)據(jù)。結(jié)果可能如下:
而兩個(gè)結(jié)果集合并以后,相當(dāng)于就獲得了全局視野,也就可以很容易的找出這一頁(yè)需要的5條數(shù)據(jù)了。
如果誰(shuí)還有更好的分庫(kù)分頁(yè)查詢的方法,也歡迎指教!
0
回答0
回答3
回答0
回答0
回答1
回答0
回答0
回答0
回答5
回答