數(shù)據(jù)庫優(yōu)化之分庫分表(異構(gòu)索引)
1_優(yōu)點(diǎn)
一般互聯(lián)網(wǎng)項(xiàng)目,隨著時(shí)間和業(yè)務(wù)的發(fā)展,數(shù)據(jù)庫中的數(shù)據(jù)量會(huì)一直增多,數(shù)據(jù)量的增多,這時(shí)因?yàn)楦蟮南到y(tǒng)開銷和更多的IO讀取會(huì)導(dǎo)致數(shù)據(jù)庫性能會(huì)急劇下降,畢竟單個(gè)機(jī)器的性能是有極限的,所以要對(duì)數(shù)據(jù)庫和表進(jìn)行拆分,使其分布在多個(gè)機(jī)器上,這樣就能支持更高的數(shù)據(jù)庫并發(fā)量.
還有,根據(jù)mysql執(zhí)行過程來說,1.我們接受到sql,2.把sql放進(jìn)等待隊(duì)列中,3.執(zhí)行sql,4.返回執(zhí)行結(jié)果.這個(gè)過程最花費(fèi)時(shí)間的是什么呢?第一,等待時(shí)間.第二,執(zhí)行時(shí)間.準(zhǔn)確的來說執(zhí)行時(shí)間會(huì)導(dǎo)致等待時(shí)間變長.
mysql中有一種機(jī)制是表鎖定和行鎖定筒扒,為什么要出現(xiàn)這種機(jī)制帚豪,是為了保證數(shù)據(jù)的完整性,我舉個(gè)例子來說吧嗅义,如果有二個(gè)sql都要修改同一張表的同一條數(shù)據(jù),這個(gè)時(shí)候怎么辦呢,是不是二個(gè)sql都可以同時(shí)修改這條數(shù)據(jù)呢?很顯然mysql對(duì)這種情況的處理是止喷,一種是表鎖定(myisam存儲(chǔ)引擎),一個(gè)是行鎖定(innodb存儲(chǔ)引擎)混聊。表鎖定表示你們都不能對(duì)這張表進(jìn)行操作弹谁,必須等我對(duì)表操作完才行。行鎖定也一樣句喜,別的sql必須等我對(duì)這條數(shù)據(jù)操作完了预愤,才能對(duì)這條數(shù)據(jù)進(jìn)行操作。如果數(shù)據(jù)太多咳胃,一次執(zhí)行的時(shí)間植康,等待的時(shí)間就越長,這也是我們?yōu)槭裁匆直淼脑颉?/p>
2_缺點(diǎn)
分庫分表并不是完美的,任何一種解決方案在解決一個(gè)問題的同時(shí)都可能會(huì)引入其他問題.
2-1.分庫
1.在執(zhí)行分庫操作后,原本邏輯關(guān)聯(lián)性很強(qiáng)的數(shù)據(jù)難免會(huì)劃分到多個(gè)庫中,這時(shí),表的關(guān)聯(lián)操作難免受到影響.因?yàn)槎鄶?shù)公司都命令禁止跨庫sql,我們無法用join做聯(lián)表操作,結(jié)果本來一次查詢能完成的業(yè)務(wù),可能需要多次查詢才能完成.
2.原本單數(shù)據(jù)庫中,可以用事務(wù)來保證一些操作的原子操作,但是執(zhí)行分庫操作后,統(tǒng)一管理將會(huì)變得困難,雖然一些大廠提供了不少跨庫的事務(wù)解決方案,但是性能上仍然有著不小的欠缺,所以很多情況下并不實(shí)用.而且多數(shù)情況下,分布式事務(wù)無法避免,根據(jù)業(yè)務(wù)情況,適當(dāng)使用分布式事務(wù).
3.分庫意味著開發(fā)和數(shù)據(jù)庫管理的工作量成倍的增加,原來只需要一個(gè)數(shù)據(jù)庫管理人員,分庫后可能需要兩個(gè)或三個(gè),導(dǎo)致公司在人力上的投入大大增加.
2-2.分表
1.數(shù)據(jù)表垂直拆分后,原來只需要一次查詢的sql可能會(huì)變成需要join的連表查詢,這會(huì)導(dǎo)致性能上的損失
2.表才分后如果遇到有order by(排序)的操作,數(shù)據(jù)庫就無能為力了,只能由業(yè)務(wù)代碼或數(shù)據(jù)庫中間件來實(shí)現(xiàn)了.
3.數(shù)據(jù)庫橫向拆分時(shí),常用的主要有兩種規(guī)則:范圍切分和哈希值切分.范圍 切分是指按照某個(gè)字段的范圍來切分展懈,比如用戶表按照用戶ID來切分销睁,ID為1到10萬的位于User1中,100001到200000萬的位于User2中存崖,這樣切分的優(yōu)勢是可以無限擴(kuò)容下去冻记,不用考慮數(shù)據(jù)遷移的問題,劣勢就是新表和舊表數(shù)據(jù)分布不均勻来惧,而且分表的范圍選取有一定難度冗栗,范圍太小會(huì)導(dǎo)致表太多,太大會(huì)導(dǎo)致問題根本上沒有解決的困惑供搀。另外一種分表策略就是把某一列按照哈希值來路由到不同的表中隅居,同樣以用戶ID為例,假如我們一開始就規(guī)劃了10個(gè)數(shù)據(jù)庫表葛虐,路由算法可以簡單地用 user_id %10的值來表示數(shù)據(jù)所屬的數(shù)據(jù)庫表編號(hào)军浆,ID為985的用戶放到編號(hào)為5的子表中,ID為10086的用戶放到編號(hào)為6的字表中挡闰。這種切分規(guī)則的優(yōu)勢是每個(gè)表的數(shù)據(jù)分布比較均勻,但是后期擴(kuò)容會(huì)設(shè)計(jì)到部分?jǐn)?shù)據(jù)的遷移工作。
3_分庫分表策略
3_1.根據(jù)業(yè)務(wù)垂直拆分
分庫策略,業(yè)務(wù)按照規(guī)則劃分好邊界,每個(gè)業(yè)務(wù)對(duì)應(yīng)的數(shù)據(jù)庫自然就誕生了.舉例:一個(gè)典型的電商系統(tǒng)可以劃分為商品,訂單,用戶等模塊.
分表策略,表也可以按照業(yè)務(wù)需求來拆分,比如一個(gè)數(shù)據(jù)庫中的訂單表,根據(jù)業(yè)務(wù)需求和訪問頻繁程度,可以劃分為,經(jīng)常要訪問的訂單數(shù)據(jù)表和不經(jīng)常訪問的訂單詳情表.
3_2.根據(jù)數(shù)據(jù)量橫向切分
橫向切分是諸多業(yè)務(wù)中最常用的切分方式摄悯,本質(zhì)是把一個(gè)表中的數(shù)據(jù)行按照規(guī)則分散到多個(gè)表中赞季,比如最常見的按照ID范圍,按照業(yè)務(wù)主鍵的哈希值等奢驯。至于表數(shù)據(jù)到達(dá)什么數(shù)量級(jí)之后進(jìn)行切分申钩,這和表中存的數(shù)據(jù)格式有關(guān),比如一個(gè)表只有幾列的int字段肯定要比幾列text類型的表存儲(chǔ)的極限要高瘪阁,姑且認(rèn)為這個(gè)極限是1000萬吧撒遣。但是作為一個(gè)系統(tǒng)的負(fù)責(zé)人或者架構(gòu)師來說,當(dāng)表的數(shù)據(jù)量級(jí)到達(dá)千萬級(jí)別要引起重視管跺,因?yàn)檫@是一個(gè)系統(tǒng)性能瓶頸的隱患义黎。
相對(duì)于數(shù)據(jù)表的橫向切分,在符合業(yè)務(wù)優(yōu)化的場景下我更傾向于做表分區(qū)豁跑,按照規(guī)則把不同的分區(qū)分配到不同的物理磁盤廉涕,這樣的話,業(yè)務(wù)里的SQL語句幾乎可以不用改動(dòng)艇拍。
4_異構(gòu)索引表
? 基于訂單數(shù)據(jù)的分庫分表場景,按照訂單id取模雖然很好地滿足了訂單數(shù)據(jù)均勻地保存在數(shù)據(jù)庫中狐蜕,但在買家查看自己訂單的業(yè)務(wù)場景中,就出現(xiàn)了全表掃描的情況卸夕,而且買家查看自己訂單的請(qǐng)求是非常頻繁的层释,必然給數(shù)據(jù)庫帶來擴(kuò)展和性能的問題,有違“盡量減少事務(wù)邊界”這一原則快集。
針對(duì)這類場景問題贡羔,最常用的是采用“異構(gòu)索引表”的方式解決,即采用異步機(jī)制將原表的每一次創(chuàng)建或更新碍讨,都換另一個(gè)維度保存一份完整的數(shù)據(jù)表或索引表治力。這是另一種解決思路:拿空間換時(shí)間。
也就是應(yīng)用在穿件或更新一條訂單ID為分庫分表鍵的訂單數(shù)據(jù)時(shí)勃黍,也會(huì)再保存一份按照買家ID為分庫分表鍵的訂單索引數(shù)據(jù)宵统,其結(jié)果就是同一買家的所有訂單索引表都保存在同一數(shù)據(jù)庫中,這就是給訂單創(chuàng)建了異構(gòu)索引表覆获。
這樣, 最終通過兩次訪問效率最高的sql請(qǐng)求代替了之前的需要進(jìn)行全表掃描的問題马澈。
有人可能會(huì)指出,為什么不是將訂單的完整數(shù)據(jù)按照買家id維度進(jìn)行一次分庫保存弄息,這樣就只需要進(jìn)行一次按照買家id維度進(jìn)行數(shù)據(jù)庫的訪問就獲取到訂單的信息了痊班?
這是一個(gè)好問題,其實(shí)淘寶的沒訂單數(shù)據(jù)就是在異構(gòu)索引表中全復(fù)制的摹量,即訂單按照買家id維度進(jìn)行分庫分表的訂單索引表跟以訂單id維度進(jìn)行分庫分表的訂單表中的字段完全一樣涤伐,這樣確實(shí)避免了多一次的數(shù)據(jù)庫訪問馒胆。但一般來說,應(yīng)用可能會(huì)按照多個(gè)維度創(chuàng)建多個(gè)異構(gòu)索引表凝果,如果全部采用全復(fù)制的方法會(huì)帶來大量的數(shù)據(jù)冗余祝迂,從而增加不少數(shù)據(jù)存儲(chǔ)成本。
? 實(shí)際場景下,也并非不可采取全復(fù)制的方式.雖然可能會(huì)帶來高額存儲(chǔ)成本,但是也能帶來相對(duì)的性能提升,可以提高數(shù)據(jù)庫并發(fā)量和用戶體驗(yàn).
擴(kuò)展鏈接,數(shù)據(jù)庫分區(qū),分庫分表,分片:https://blog.csdn.net/qq_28289405/article/details/80576614