日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

MySQL分库分页_MySQL分库分表的分页查询解决方案

發(fā)布時(shí)間:2025/3/17 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL分库分页_MySQL分库分表的分页查询解决方案 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

問(wèn)題的提出

我們知道,當(dāng)我們的數(shù)據(jù)量達(dá)到一定數(shù)量時(shí),需要將數(shù)據(jù)表進(jìn)行水平拆分,從而滿足大量數(shù)據(jù)的存儲(chǔ)和查詢,保證系統(tǒng)的可用性,但同時(shí)會(huì)出現(xiàn)另外一個(gè)問(wèn)題就是,如果業(yè)務(wù)要查詢“最近注冊(cè)的第3頁(yè)用戶”,該如何實(shí)現(xiàn)呢?單庫(kù)上,可以通過(guò)簡(jiǎn)單的sql實(shí)現(xiàn)分頁(yè)查詢。

select * from t_user order by time limit 200,100

1

select *fromt_userorderbytimelimit200,100

分庫(kù)分表后變成兩個(gè)庫(kù)后,分庫(kù)依據(jù)是user_id,排序依據(jù)是time,單個(gè)分?jǐn)?shù)據(jù)庫(kù)層失去了time排序的全局視野,如果同樣需要實(shí)現(xiàn)分頁(yè)查詢時(shí)該怎么辦呢?有什么比較好的MySQL分庫(kù)分表的分頁(yè)查詢解決方案呢?

全局視野法

正常來(lái)講,不管哪一個(gè)分庫(kù)的第3頁(yè)都不一定有全局第3頁(yè)的所有數(shù)據(jù),例如一下三種情況:

情況一:兩個(gè)分庫(kù)按照時(shí)間排序,數(shù)據(jù)各占一半,則每頁(yè)取offset和limit的一般數(shù)據(jù)回來(lái)合并就可以了

情況二:所有數(shù)據(jù)都在一個(gè)庫(kù)上,則取一個(gè)庫(kù)的所有數(shù)據(jù)回來(lái)就可以了

情況三,那么一般情況是,每個(gè)分庫(kù)的數(shù)據(jù)數(shù)據(jù)是隨機(jī)的,但是一定是在全局offset=600之內(nèi)

由于不清楚到底是哪種情況,所以必須每個(gè)庫(kù)都返回3頁(yè)數(shù)據(jù),所得到的6頁(yè)數(shù)據(jù)在服務(wù)層進(jìn)行內(nèi)存排序,得到數(shù)據(jù)全局視野,再取第3頁(yè)數(shù)據(jù),便能夠得到想要的全局分頁(yè)數(shù)據(jù)。

這種方法缺點(diǎn)是:當(dāng)查詢的頁(yè)數(shù)增大時(shí),每個(gè)分庫(kù)所需返回的數(shù)據(jù)也越來(lái)成倍增加,降低了查詢的性能

業(yè)務(wù)折中

第一種折中的方案是

對(duì)全局視野法的一種優(yōu)化,即禁用制定頁(yè)數(shù)的分頁(yè)查詢,必須通過(guò)下一頁(yè)來(lái)實(shí)現(xiàn)分頁(yè)查詢的頁(yè)數(shù)跳轉(zhuǎn),并且在每次查詢下一頁(yè)時(shí)將上一頁(yè)的最大排序字段的值帶上(這里就是時(shí)間time),這樣在每個(gè)分庫(kù)查詢數(shù)據(jù)時(shí)待上這個(gè)條件,可以優(yōu)化查詢速率。

第二種折中的方案是

數(shù)據(jù)庫(kù)分庫(kù)-數(shù)據(jù)均衡原理

使用patition key進(jìn)行分庫(kù),在數(shù)據(jù)量較大,數(shù)據(jù)分布足夠隨機(jī)的情況下,各分庫(kù)所有非patition key屬性,在各個(gè)分庫(kù)上的數(shù)據(jù)分布,統(tǒng)計(jì)概率情況是一致的。

例如,在uid隨機(jī)的情況下,使用uid取模分兩庫(kù),db0和db1:

(1)性別屬性,如果db0庫(kù)上的男性用戶占比70%,則db1上男性用戶占比也應(yīng)為70%

(2)年齡屬性,如果db0庫(kù)上18-28歲少女用戶比例占比15%,則db1上少女用戶比例也應(yīng)為15%

(3)時(shí)間屬性,如果db0庫(kù)上每天10:00之前登錄的用戶占比為20%,則db1上應(yīng)該是相同的統(tǒng)計(jì)規(guī)律

利用這一原理,要查詢?nèi)?00頁(yè)數(shù)據(jù),offset 9900 limit 100改寫為offset 4950 limit 50,每個(gè)分庫(kù)偏移4950(一半),獲取50條數(shù)據(jù)(半頁(yè)),得到的數(shù)據(jù)集的并集,基本能夠認(rèn)為,是全局?jǐn)?shù)據(jù)的offset 9900 limit 100的數(shù)據(jù),當(dāng)然,這一頁(yè)數(shù)據(jù)的精度,并不是精準(zhǔn)的。

根據(jù)實(shí)際業(yè)務(wù)經(jīng)驗(yàn),用戶都要查詢第100頁(yè)網(wǎng)頁(yè)、帖子、郵件的數(shù)據(jù)了,這一頁(yè)數(shù)據(jù)的精準(zhǔn)性損失,業(yè)務(wù)上往往是可以接受的,但此時(shí)技術(shù)方案的復(fù)雜度便大大降低了,既不需要返回更多的數(shù)據(jù),也不需要進(jìn)行服務(wù)內(nèi)存排序了。

二次查找法

有沒(méi)有一種方法既能滿足業(yè)務(wù)要求,并且不需要折中,性能還高的方法呢?

接下來(lái)介紹一種“二次查找法”,不知道能不能講的明白,我盡量吧。

為了方便舉例,假設(shè)一頁(yè)只有5條數(shù)據(jù),查詢第200頁(yè)的SQL語(yǔ)句為select * from T order by time offset 1000 limit 5;

分五步:

1. 將select * from T order by time offset 1000 limit 5; 優(yōu)化成select * from T order by time offset 500 limit 5,注意這里的500=1000/分表數(shù)量,并將這個(gè)sql下發(fā)至每個(gè)分庫(kù)分表中執(zhí)行,每個(gè)分庫(kù)返回這個(gè)sql執(zhí)行的結(jié)果。

2. 找到所有分庫(kù)返回結(jié)果的time的最小值

第一個(gè)庫(kù),5條數(shù)據(jù)的time最小值是1487501123

第二個(gè)庫(kù),5條數(shù)據(jù)的time最小值是1487501223

故,三頁(yè)數(shù)據(jù)中,time最小值來(lái)自第一個(gè)庫(kù),time_min=1487501123,這個(gè)過(guò)程只需要比較各個(gè)分庫(kù)第一條數(shù)據(jù),時(shí)間復(fù)雜度很低

3. 查詢二次改寫

第一次改寫的SQL語(yǔ)句是select * from T order by time offset 500 limit 5

第二次要改寫成一個(gè)between語(yǔ)句,between的起點(diǎn)是time_min,between的終點(diǎn)是原來(lái)每個(gè)分庫(kù)各自返回?cái)?shù)據(jù)的最大值:

第一個(gè)分庫(kù),第一次返回?cái)?shù)據(jù)的最大值是1487501523

所以查詢改寫為select * from T order by time where time between time_min and 1487501523

第二個(gè)分庫(kù),第一次返回?cái)?shù)據(jù)的最大值是1487501699

所以查詢改寫為select * from T order by time where time between time_min and 1487501699

從上面圖片可以看出,DB1比第一次查出來(lái)的數(shù)據(jù)多了兩行,應(yīng)為查詢的范圍擴(kuò)大了

4. 計(jì)算time_min這條記錄在全局的offset

根據(jù)第一步查詢的sqlselect * from T order by time offset 500 limit ,我們知道每個(gè)庫(kù)的offset值了,將DB0中的最小time的數(shù)據(jù)虛擬到DB1中推算在DB1中的offset值=497

從而我們得知time_min這條記錄在全局的offset值=500+497=997

5. 根據(jù)第二次查詢出來(lái)的結(jié)果集,在內(nèi)存中作排序,已知time_min在全局中的offset=997,那么結(jié)果集排序之后也能推算出offset=1000所在的記錄,從而獲得sqlselect * from T order by time offset 1000 limit 5的分頁(yè)查詢記錄(圖片黃色部分)

總結(jié):可以精確的返回業(yè)務(wù)所需數(shù)據(jù),每次返回的數(shù)據(jù)量都非常小,不會(huì)隨著翻頁(yè)增加數(shù)據(jù)的返回量。

瀏覽量:

7

0

總結(jié)

以上是生活随笔為你收集整理的MySQL分库分页_MySQL分库分表的分页查询解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。