mysql为什么要分库_我们为什么要分库分表
當(dāng)一張表的數(shù)據(jù)達(dá)到幾千萬時(shí),查詢一次所花的時(shí)間會(huì)變長。這時(shí)候,如果有聯(lián)合查詢的話,可能會(huì)卡死在那兒,甚至把系統(tǒng)給拖垮。
而分庫分表的目的就在于此:減小數(shù)據(jù)庫的負(fù)擔(dān),提高數(shù)據(jù)庫的效率,縮短查詢時(shí)間。另外,因?yàn)榉謳旆直磉@種改造是可控的,底層還是基于RDBMS,因此整個(gè)數(shù)據(jù)庫的運(yùn)維體系以及相關(guān)基礎(chǔ)設(shè)施都是可重用的。
目前我們系統(tǒng)將近20億數(shù)據(jù),每張表最大的接近600w條/表,每條數(shù)據(jù)大約3k,每個(gè)表將近1.5G的數(shù)據(jù)。查詢經(jīng)常超時(shí),單條SQL執(zhí)行count(*)查詢時(shí)間達(dá)到了最大260ms,0.26s(標(biāo)準(zhǔn)是超過0.1s的數(shù)據(jù)為慢SQL)。
為了說明我們?yōu)槭裁匆謳旆直?#xff0c;我們看一下sql的執(zhí)行過程。
mysql執(zhí)行一條sql的過程如下:
1、收到sql
2、把sql放到排隊(duì)隊(duì)列中
3、執(zhí)行sql
4、返回結(jié)果
在這個(gè)執(zhí)行過程中最花時(shí)間的地方在于:
1.排隊(duì)等待的時(shí)間,
2.sql的執(zhí)行時(shí)間。
如果有2個(gè)sql都要同時(shí)修改同一張表的同一條數(shù)據(jù),mysql對(duì)這種情況的處理是:一種是表鎖定(MyISAM存儲(chǔ)引擎),一個(gè)是行鎖定(InnoDB存儲(chǔ)引擎)。
表鎖定表示其他操作都不能對(duì)這張表進(jìn)行操作,必須等當(dāng)前對(duì)表的操作完才行。行鎖定也一樣,別的sql必須等這條數(shù)據(jù)操作完了,其他人才能對(duì)這條數(shù)據(jù)進(jìn)行操作。
如果數(shù)據(jù)太多,一次執(zhí)行的時(shí)間太長,等待的時(shí)間就越長,這也是我們?yōu)槭裁匆直淼脑颉?/p>
分庫分表術(shù)語:
讀寫分離:?不同的數(shù)據(jù)庫,同步相同的數(shù)據(jù),分別只負(fù)責(zé)數(shù)據(jù)的讀和寫;
分區(qū):指定分區(qū)列表達(dá)式,把記錄拆分到不同的區(qū)域中(必須是同一服務(wù)器,可以是不同硬盤),應(yīng)用看來還是同一張表,沒有變化;
分庫:一個(gè)系統(tǒng)的多張數(shù)據(jù)表,存儲(chǔ)到多個(gè)數(shù)據(jù)庫實(shí)例中;
分表:?對(duì)于一張多行(記錄)多列(字段)的二維數(shù)據(jù)表,又分兩種情形:
垂直分表: 豎向切分,不同分表存儲(chǔ)不同的字段,可以把不常用或者大容量、或者不同業(yè)務(wù)的字段拆分出去;水平分表(最復(fù)雜): 橫向切分,按照特定分片算法,不同分表存儲(chǔ)不同的記錄。在實(shí)際生產(chǎn)中,通常的進(jìn)化過程是:單庫單表->單庫多表->多庫多表;;分區(qū)->分表->分庫(垂直分庫 - 水平分庫 - 讀寫分離)
單庫單表
單庫單表是最常見的數(shù)據(jù)庫設(shè)計(jì),例如,有一張訂單表(order)放在數(shù)據(jù)庫中,所有的訂單都可以在order表中查到。
單庫多表
隨著訂單數(shù)量的增加,order表的數(shù)據(jù)量會(huì)越來越大,當(dāng)數(shù)據(jù)量達(dá)到一定程度的時(shí)候,對(duì)order表的查詢會(huì)變慢,從而影響整個(gè)DB的性能。
另外,隨著需求的迭代,如果增加添加一列的時(shí)候,mysql會(huì)鎖表,期間所有的讀寫操作只能等待,別無他法。
這時(shí)候,可以將order進(jìn)行水平的切分,產(chǎn)生多個(gè)表結(jié)構(gòu)完全一樣的order表。比如:order_01,order_02....,order_n,那么order_01+order_02+order_n的數(shù)據(jù)是一份完整的訂單數(shù)據(jù)。
這個(gè)水平切分,簡單的做法如:
按數(shù)量切分,1~1000的存在第一張表,1001~2000存在第二張表;
按時(shí)間切分,比如:2019年1月份存在第一張表,2019年2月份存在第二張表;還可以按照id的哈希值進(jìn)行切分,等等等等
多庫多表
隨著數(shù)據(jù)量增加,單臺(tái)數(shù)據(jù)庫的硬件存儲(chǔ)不夠了,并且,隨著查詢量的增加,單臺(tái)數(shù)據(jù)庫服務(wù)器已經(jīng)沒辦法支撐。這時(shí)候就需要對(duì)數(shù)據(jù)庫進(jìn)行水平區(qū)分。
比如按地區(qū)分庫,一個(gè)省份在一個(gè)物理數(shù)據(jù)庫等等
任何事情都有兩面性,分庫分表也不例外,如果采用分庫分表,會(huì)引入新的的問題
1.分布式事務(wù)問題
做了垂直分庫或者水平分庫以后,就必然會(huì)涉及到跨庫執(zhí)行SQL的問題,就會(huì)引發(fā)互聯(lián)網(wǎng)界的老大難問題-"分布式事務(wù)"。那么要如何解決這個(gè)問題呢?
使用分布式事務(wù)中間件使用MySQL自帶的針對(duì)跨庫的事務(wù)一致性方案(XA),不過性能要比單庫的慢10倍左右。能否避免掉跨庫操作(比如將用戶和商品放在同一個(gè)庫中)2.跨庫join的問題
分庫分表后,表之間的關(guān)聯(lián)操作將受到限制,就無法join位于不同分庫的表,也無法join分表粒度不同的表, 結(jié)果原本一次查詢能夠完成的業(yè)務(wù),可能需要多次查詢才能完成。
那么要如何解決這個(gè)問題呢?
簡單的解決方法:
全局表:基礎(chǔ)數(shù)據(jù),所有庫都拷貝一份。字段冗余:把需要join的字段冗余在各個(gè)表中,這樣有些字段就不用join去查詢了。系統(tǒng)層組裝:應(yīng)用端先分別查詢出所有復(fù)核條件的,然后在應(yīng)用端組裝起來,類似于一個(gè)mapreduce的過程(較復(fù)雜)。3.橫向擴(kuò)容的問題
當(dāng)我們使用哈希取模做分表的時(shí)候,針對(duì)數(shù)據(jù)量的遞增,可能需要?jiǎng)討B(tài)的增加表,此時(shí)就需要考慮數(shù)據(jù)遷移的問題。
原來使用的是hash后對(duì)8進(jìn)行取模,那么,數(shù)據(jù)是均分在8個(gè)表(庫)上。
如果8個(gè)表不夠的時(shí)候,我們要擴(kuò)展到16個(gè)表,這時(shí)候,我們hash后對(duì)16取模,新數(shù)據(jù)是沒有問題的,舊數(shù)據(jù)就會(huì)發(fā)生錯(cuò)亂。
如果哈希后是9,那么,原來我們對(duì)8取模后,是1,會(huì)到表1進(jìn)行查詢;但是,現(xiàn)在我們是對(duì)16取模,那么是到表9進(jìn)行查詢的,而這個(gè)數(shù)據(jù)在表9又不存在,因此,就會(huì)找不到數(shù)據(jù)了
4.結(jié)果集合并、排序的問題
因?yàn)槲覀兪菍?shù)據(jù)分散存儲(chǔ)到不同的庫、表里的,當(dāng)我們查詢指定數(shù)據(jù)列表時(shí),數(shù)據(jù)來源于不同的子庫或者子表,就必然會(huì)引發(fā)結(jié)果集合并、排序的問題。
如果每次查詢都需要排序、合并等操作,性能肯定會(huì)受非常大的影響。
上面列出了分庫分表的常見的一些,總的來說:
能不切分盡量不要切分,如果沒有達(dá)到幾百萬,通常無需分庫分表如果一定要切分,一定要選擇合適的切分規(guī)則,提前規(guī)劃好。如果一定要切分,盡量通過數(shù)據(jù)冗余或表分組來降低跨庫 Join 的可能。對(duì)于現(xiàn)在市面上有好幾種數(shù)據(jù)庫中間件,這些中間件對(duì)數(shù)據(jù) Join 實(shí)現(xiàn),個(gè)中滋味,只能自己體會(huì)。業(yè)務(wù)讀取盡量少使用多表 Join。數(shù)據(jù)盡可能的比較均勻分布數(shù)據(jù)到各個(gè)節(jié)點(diǎn)上
總結(jié)
以上是生活随笔為你收集整理的mysql为什么要分库_我们为什么要分库分表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: java vue20.2.2浏览器_支持
- 下一篇: mysql将权限分为几个层级_MySQL
