分庫(kù)分表的策略,依項(xiàng)目需求而定,這里采用的是常規(guī)的做法:根據(jù)取模的方式,假設(shè)我們水平分庫(kù)2個(gè),每個(gè)庫(kù)又水平拆表2個(gè) 既總共有4個(gè)表,查詢的時(shí)候默認(rèn)沒(méi)有按照其他的條件進(jìn)行排序,假設(shè)我們要查詢第41頁(yè)的數(shù)據(jù),每頁(yè)顯示10條數(shù)據(jù)
第一種:
也是最簡(jiǎn)單的一種:通過(guò)額外的添加一張關(guān)聯(lián)表,屬性中必有id屬性,至于是否有庫(kù)id屬性和表id屬性(既第幾個(gè)庫(kù)和第幾個(gè)表)可有可無(wú),因?yàn)檫@個(gè)可以根據(jù)id自行取模獲取,注意這張表存放的數(shù)據(jù)是所有數(shù)據(jù),但是勝在屬性列少,只有提供索引的幾個(gè)屬性列,這樣的話我們只需要select * from brand_temp where … limit 400,10(插敘第41頁(yè)的數(shù)據(jù),每頁(yè)顯示5條數(shù)據(jù)),然后我們獲取了id之后就可以去對(duì)應(yīng)的表中查詢了
第二種:
最耗費(fèi)性能的一種,如果我們要查詢第一頁(yè)的記錄,單庫(kù)單表的sql為:select * from db limit 0,10; 當(dāng)我們分庫(kù)分片之后 語(yǔ)句還是同樣的語(yǔ)句,但是這時(shí)候我們需要對(duì)4個(gè)表返回的記錄在內(nèi)存中進(jìn)行解析,然后通過(guò)id進(jìn)行升序,取得前10條數(shù)據(jù)返回…數(shù)據(jù)量小,頁(yè)碼小的時(shí)候很ok,但是如果我們要查詢第2頁(yè)的數(shù)據(jù)的時(shí)候,sql單體架構(gòu)的情況下為:select * from db limit 10,10; 但是在分布式數(shù)據(jù)庫(kù)這樣是不行的,數(shù)據(jù)很明顯會(huì)丟失,彌補(bǔ)的方法是查詢所有,sql語(yǔ)句為select * from db_x limit 0,10+10 //意味著需要查詢的是本在單體架構(gòu)上要查詢的記錄數(shù)加上之前的記錄 ,然后再在內(nèi)存中合并所有表返回的記錄然后進(jìn)行解析,最后取第10開(kāi)始的記錄 …可以看出這個(gè)方案一旦頁(yè)碼數(shù)達(dá)到n頁(yè),而每頁(yè)顯示的記錄數(shù)為m條記錄的時(shí)候,每個(gè)表需要查詢的記錄數(shù)為:(n-1)*m+m=nm條記錄,內(nèi)存中需要解析的記錄數(shù)為 t * n * m 條記錄,cpu不爆炸算我輸
第三種:
采取的是基于業(yè)務(wù)的模式:迫使用戶無(wú)法進(jìn)行跳頁(yè)查詢,什么意思呢,就是用戶只能點(diǎn)擊下一頁(yè)或者上一頁(yè)的方式瀏覽,具體的做法在于查詢得到記錄數(shù)的同時(shí)記錄下當(dāng)前唯一id值的最大值,然后再次查詢的時(shí)候添加where 條件…讓我們從頭開(kāi)始捋: 第一次查詢pageNum=1,pageSize=10 ,maxId=0->sql:select * from db_x where id>0 limit 10; 然后分發(fā)到對(duì)應(yīng)的庫(kù)的表中,將得到的4*10條數(shù)據(jù)合并,再在內(nèi)存中進(jìn)行解析排序,取前10條數(shù)據(jù),同時(shí)將第10條數(shù)據(jù)的id=maxId單獨(dú)取出渲染到前端頁(yè)面上保存,這樣當(dāng)點(diǎn)擊下一頁(yè)的時(shí)候,這個(gè)maxId=10也提交上去了,sql 變成了select * from db_x where id>10 limit 10,然后繼續(xù)解析,繼續(xù)保存…這種方式返回的數(shù)據(jù)都是穩(wěn)定的并且數(shù)據(jù)是連貫的(排序)
第四種:
傳說(shuō)中的最好的方式,支持跳頁(yè)查詢,這個(gè)方式核心在于2次sql查詢,具體怎么做呢:
前提條件假設(shè):查詢第1001頁(yè)的數(shù)據(jù),每頁(yè)顯示10條記錄
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1):我們先記錄下要查詢的記錄數(shù)的范圍:(1001-1)*10=10000 開(kāi)始,10010結(jié)束->10000-10010
單體的sql為:select * from db limit 10000,10;
我們總共有4個(gè)表,意味著:每個(gè)表的start應(yīng)該為10000/4=2500,從而sql變成了:
select * from db_x limit 2500,10; //假設(shè)是平均分配的,因而我們可以均分,不均分也沒(méi)關(guān)系,后續(xù)操作會(huì)補(bǔ)齊
我們會(huì)得到4個(gè)表中的記錄:(因?yàn)槲襠emo還沒(méi)寫,所以先手寫了)
T1:(1,"a"),.......
T2:(2,"b"),.......
T3:(3,"c"),.......
T4:(4,"d"),.......
真實(shí)數(shù)據(jù)第1001頁(yè)不可能是1開(kāi)頭的,將就著看吧,過(guò)幾天會(huì)一起講rabbitMQ分布式一致性和這個(gè)demo一起發(fā)布的
ok,第一階段的sql查詢結(jié)束
2):對(duì)4個(gè)表中返回的記錄進(jìn)行id匹配(id如果非整型,自行用hashCode匹配),因?yàn)槭巧虿樵?所以我們只需要比較下每個(gè)表的首條記錄
的id值即可,獲得了最小的minId=1,和各個(gè)表最大的那個(gè)值maxId;ok,轉(zhuǎn)換sql思路,這里我們采用條件查詢了(彌補(bǔ)操作第一步):
select * from db_x where id between minId and maxId 這樣我們就獲取到了遺漏的數(shù)據(jù)(當(dāng)然有多余的數(shù)據(jù))
這樣我們4個(gè)表中就返回了可能記錄數(shù)各不相同的記錄,第二步結(jié)束
3):
之后記錄minId出現(xiàn)的位置,如T1出現(xiàn)的位置為2500,T2出現(xiàn)的位置為2500-2=2048 ,T3出現(xiàn)的位置為2500-3=2047 ,T4出現(xiàn)的位置
為2500-3=2047 則最終出現(xiàn)的記錄數(shù)為:2500+2048+2047+2047=10000-2-3-3=9992,因此我們需要的查詢的記錄數(shù)需要從9992 依次往后取
8個(gè)開(kāi)始,然后再取10個(gè)就是所求的數(shù)據(jù),這種方式能做到數(shù)據(jù)精確查詢,但是唯一的缺點(diǎn)就是每次查詢都需要進(jìn)行二次sql查詢
萬(wàn)動(dòng)力(www.lu123123.com),專業(yè)的logo免費(fèi)設(shè)計(jì)在線生成網(wǎng)站,全自動(dòng)智能化logo設(shè)計(jì),商標(biāo)設(shè)計(jì),logo在線生成!
歡迎使用萬(wàn)動(dòng)力制作屬于您公司自己的logo,不僅專業(yè)而且經(jīng)濟(jì)實(shí)惠,全方位滿足您公司品牌化、視覺(jué)化的需求。