早在公元前五百年,孫子就參透了數(shù)據(jù)庫分區(qū)的真諦
數(shù)據(jù)庫分區(qū),我覺得是一個稱得上“偉大”的數(shù)據(jù)庫存儲結構概念。
如果說,一個編程者(并非一個職業(yè)DBA)除了關注表結構本身以外,分區(qū),可能就是所需要關注的最靠近底層的一個數(shù)據(jù)庫的設計。
例如像數(shù)據(jù)庫的表空間這樣的概念,通常一個普通開發(fā)人員,就未必會去關注。但是分區(qū)概念卻不一樣,因為它與應用場景結合更加緊密。比如,按時間、按地區(qū)、按類別分區(qū),等等。
我猜測很多人是不贊同「數(shù)據(jù)庫分區(qū)是個“偉大”的概念」這個觀點的。原因是,我翻閱了各種市面上主流數(shù)據(jù)庫的書籍,入門級的如《XX數(shù)據(jù)庫從入門到刪庫跑路》,看起來高端的如《XX數(shù)據(jù)庫的技術內幕》,大部分書籍在介紹分區(qū)的內容的時候,都沒有給很大的篇幅。
甚至有好幾本書上,就這么簡單的來了一句:對于一個很大的表,如果每次搜索都對全表進行掃描,會很耗時間,如果分區(qū)了之后,只要訪問某個分區(qū)就會很快。
這難道不是一種誤導么?分區(qū)真的能這么簡單就講清楚嗎?我覺得當然不是,所以本文的內容就是想說說我認為的,分區(qū)的重要和偉大之處。
一、數(shù)據(jù)庫為什么要有分區(qū)?
在《孫子兵法》的第五篇 —《兵勢篇》中,孫子曰:凡治眾如治寡,分數(shù)是也。斗眾如斗寡,形名是也。
說人話:凡是在管理很大的數(shù)據(jù)庫表時就和管理小的數(shù)據(jù)庫表時一樣,把它分區(qū)就好了;發(fā)揮好所有分區(qū)的功能就和發(fā)揮好其中一個分區(qū)的功能一樣,他們能有一個統(tǒng)一的表名,可以使用統(tǒng)一的SQL語句來調度就好了。
上面這段話,從分號隔開,可以分成上下兩句。那么“偉大”是在于前半句還是后半句呢?顯然是后半句。為啥?你把人分了容易,但是你要把茫茫多的已經(jīng)分開的人,指揮得像一個人一樣,這件事情就偉大了。
1、考慮隔離與瓶頸
好,先討論上半句,分治的思想。我常常遇到這樣的對話場景。
場景一:
對話者:“我們的數(shù)據(jù)太大了,我們分表吧!”
我:“為什么不用分區(qū)呢?”
對話者:“分區(qū)可以解決嗎?”(請自己腦補不信任的眼神和質疑的語氣)
場景二:
演講者:“我們考慮用***進的分庫技術理念來解決這個瓶頸”。
眾人投去了羨慕嫉妒而又膜拜的眼神,等待著大神講出華麗又牛叉的方案。
我:“這里有個瓶頸,我們需要給這個表分區(qū)。”
眾人輕視又不懈說,好的,那分一下吧。
其實無論是分區(qū)、分表還是分庫,我們都需要圍繞兩個重要概念,一是隔離,一是瓶頸。
在場景一種,為什么使用者要求分表呢?常見的情況中,例如,我這兩個表,雖然結構一樣,但是我一個是北京的數(shù)據(jù),一個是上海的數(shù)據(jù)。如果北京的數(shù)據(jù)壞了,或者,我在對北京的數(shù)據(jù)進行奇奇怪怪的操作的時候,我需要對上海的數(shù)據(jù)完全沒有影響,這就是所謂隔離。
又比如,可能全國的數(shù)據(jù)放在一起量太大,交易量太多,出現(xiàn)了,磁盤、IO、網(wǎng)絡、CPU等撐不住的情況,這就是所謂瓶頸。
分區(qū)、分表、分庫滿足的是不同的隔離級別,以及解決不同的瓶頸。但是,他們的思想是非常接近的。
2、Partition與Sharding
Sharding這個詞(通常譯為分片),可以說是自帶高貴的屬性。每當與人討論數(shù)據(jù)庫技術,一聊到Sharding,就有一種自然而然上檔次的感覺。
而且,它有很多好朋友,說出來各個華麗無比,比如分布式、集群、大數(shù)據(jù)等等。
而Partition這個詞,雖然從很多角度上來看,都很類似于Sharding,或者說它們都是從“分數(shù)是也”的理念而來。但就是感覺LOW。
為啥?按我的理解,因為Partition的實現(xiàn)是由DBMS來完成的,使用者沒感覺。而Sharding往往需要程序,設計模式,乃至整個架構的設計圍繞著它服務,十分有存在感。
那它們在實際運用的時候有區(qū)別嗎?當然有!那么什么時候應該Sharding,什么時候應該Partition呢?
我個人覺得Sharding的使用有兩種情況,***種叫沒錢的時候,第二種是Partition用到***,也搞不定的時候。
那么Partition什么時候搞不定呢?又有兩種,一種叫沒錢的時候,第二種叫超過了當今世上的硬件極限(買最貴的設備都抗不住)的時候。
1)沒錢的時候
我們細細思量可以發(fā)現(xiàn),分庫分表這個套路在什么數(shù)據(jù)庫上用的范圍最廣?或者你在什么地方見得會比較多?我覺得通常會指到同一個地方,叫MySQL。
雖然它有各種各樣華麗的馬甲,比如騰訊的TDSQL。為什么要用MySQL?因為開源免費。什么?InnoDB也很強大?如果明天Oracle開源免費,你選型的時候還會選MySQL?
不扯遠了,MySQL為啥有那么多分庫分表呢?我認為真相只有這一個。因為5.1版之前,MySQL不支持分區(qū)。這就是我說的***種情況,叫沒錢的時候,Oracle、SQL Server、DB2我通通買不起。好了,下一個免費的MySQL,做分庫分表。
拋開玩笑的內容,Partition確實有解決不掉瓶頸需要使用分庫分表的時候。但是,一個成熟的數(shù)據(jù)庫使用者不應該濫用分庫分表。這就是所謂DBA界分庫鐵律***條,我非常贊同,叫做:能不分,就不分。然后,說說,第二種,Partition用到了***的場景。
2)超過當前硬件極限
簡單的說,我買了個Oracle,但是我的系統(tǒng)TPS要1萬。在X86上跑Oracle,撐不住怎么辦?
那么出路兩條,***條,Exadata了解一下?IBM主機買一臺?買不起,好,我們在MySQL,或者X86上用Oracle做分庫分表,這就是第二類里面的沒錢的時候。
還有一種就是Exadata、IBM主機撐不住,所謂超越了地球上科技產(chǎn)品的極限,反正我沒見過。
3、分庫、分表、分區(qū)的使用場景
看到這里,是不是覺得扯淡內容太多了。到底什么情況分區(qū)?什么情況分表?什么時候分庫呢?還是那句話,***看隔離級別,第二看瓶頸。前一段主要說的是瓶頸場景,那么從隔離級別上來看呢?
1)分庫選擇
兩份結構一樣的數(shù)據(jù)。但他屬于兩個客戶,客戶說,我有監(jiān)管要求,我不能把數(shù)據(jù)和別人的數(shù)據(jù)放在一起,必須絕對的隔離,有嚴格的訪問控制,別人根本不能有我的DB服務器的登陸權限。
這就要求,數(shù)據(jù)在數(shù)據(jù)庫層面就完全的隔開,就可以用分庫。
2)分表選擇
如果說我是一個云提供商,兩個客戶都用我的客戶,他們分別有自己的用戶(Schema),他們允許和他人共用數(shù)據(jù)庫服務器,但是,嚴禁其他人使用歸屬于他的數(shù)據(jù)庫表。
那么這時候,可以分表。
3)分區(qū)選擇
如果,兩份數(shù)據(jù)要求簡單的隔離,相互處理不影響就可以了,有時候,我還希望一個用戶一條SQL,就能對比分析他們的差異。
那這時候,分區(qū)就是一個***的選擇。
二、數(shù)字庫分區(qū)的優(yōu)勢
接下來講后半部分,斗眾如斗寡,形名是也。
1、分區(qū)的同時處理掉技術關口
斗眾如斗寡,這句話講起來簡單,實現(xiàn)起來可不是那么簡單。在主流的DBMS里面,不同的分區(qū)意味著不同的對象(如Oracle中,不同的Segment,DB2分區(qū)表不同分區(qū)對應數(shù)據(jù)文件)。
不夸張的說,很多數(shù)據(jù)庫中間件產(chǎn)品,在反復糾纏、實現(xiàn)的內容,其本身就是主流DBMS在分區(qū)時要處理掉的技術關口。
比如有:跨庫的SQL重寫,一個運行在分布式場景的SQL,需要被中間件重寫成多個SQL,丟到多個庫去執(zhí)行。尤其是,跨庫的連結、聚合(包括Max、Min、Sum、Count)。其實在多分區(qū)的時候,一樣存在這樣的問題。
如果說這個問題,不太容易被開發(fā)者所關注到。再舉一個例子:全局/本地索引。
在DBMS中,全局索引通常是要在設計上有所回避的。一般數(shù)據(jù)表一旦分區(qū),意味著數(shù)據(jù)量比較大。例如最常見的B樹索引,全局索引意味索引層次多,查詢速度慢。
但是當無論如何,我在查詢時,無法送入分區(qū)KEY時,全局索引總歸還是***的選擇。而在分布式場景里,沒有分庫KEY就會非常尷尬,要么查不了,要么就要遍歷所有的庫,這個代價幾乎就是不可接受的。
2、分區(qū)與優(yōu)化密不可分
分區(qū)和分庫面臨的很多問題都存在著巨大的相似之處,開發(fā)者總是會重視分庫所面臨問題和困難,然而普遍會輕視分區(qū)可能帶來的副作用。
我常常被質問,數(shù)據(jù)多了,為什么不加分區(qū)!?并發(fā)有沖突,為什么不加分區(qū)!?程序速度慢了,為什么不加分區(qū)!?PS:這一系列的質問,同樣適用于為什么不加索引系列。
這種輕視源自于,主流DBMS系統(tǒng)對分區(qū)功能的很好的支撐。作為DBA,比較害怕的是有人懂一點數(shù)據(jù)庫,且特別自信的站在他自己立場來和我討論。
有一些開發(fā)者傳遞給我一個理念,分區(qū)多比分區(qū)少要好。只要用了分區(qū),就能更快,至少不可能更差!開發(fā)者在說起這些的時候,非常的自信。
其實,在我看來分區(qū)設計和查詢優(yōu)化是密切相關的。分區(qū)設計一定是與特定的查詢場景匹配,才能達到好的結果。
比如之前提到的沒有分區(qū)列送入的查詢需要逐個遍歷每個分區(qū),再比如說Hash分區(qū)后的范圍查找。
Oracle中索引的Hash分區(qū),在大規(guī)模的高并發(fā)插入的數(shù)據(jù)庫表上應用十分常見,因為這種場景非常容易產(chǎn)生沖突事件 ,使用Hash分區(qū)之后,可以極大的緩解。然而這也挖下了一個坑,那就是這個索引上的范圍查找就變得不那么理想。
由此推論,分區(qū)上可以能遇到的大坑,其實在分庫的場景同樣使用。
比如說,做了分庫,卻發(fā)現(xiàn)交易的業(yè)務場景拿不到Sharding Key。采用了Hash的算法,算Sharding Key,又突然發(fā)現(xiàn)有個交易要范圍查Sharding Key,以至于可能要去各個庫兜一圈。
分區(qū)面對的坑,可以說在分庫場景下,是急劇放大了。所以,不可以隨意濫用分區(qū),更加不可以隨便亂分庫。
3、容錯率提高
反過來講,我為何在開篇說分區(qū)十分偉大,尤其是Oracle。在你違背了種種優(yōu)化原則之后,做了NPI,做了跨分區(qū)的JOIN等等。盡管有性能上的損失,無論如何,數(shù)據(jù)庫都幫你把那些復雜的工作給完成了。
當你的需求不是實時響應時,這些奇奇怪怪的跨分區(qū)要解決的問題,Rdbms都還是透明的把這些工作給你做完了,這怎么能不說它是偉大的呢?這一點我想那些開發(fā)分布式數(shù)據(jù)庫中間件的人,最能認同。
三、寫在***
***寫到這里,作為一個DBA,我特別希望給程序開發(fā)者傳遞一個理念,那就是這世界上一定沒有一個***的優(yōu)化方案。
你要一個表,又能高并發(fā)插入,又能做各種各樣高效的查詢,一會范圍,一會模糊。我只想說,這是不可能的。所有優(yōu)化方案都是以犧牲某一種性能來換另一種性能。
而DBA的職責,就是搞清楚業(yè)務需要什么,不需要什么。犧牲掉不需要的功能,換取需要的功能,甚至于犧牲不常用的功能,換取優(yōu)異的常用功能。這其實就是***的方案,分區(qū)也不例外。
在本文的***,我想留一個我一直困惑的問題。在我看了無數(shù)篇分庫分表放在一起的文章和帖子之后,我開始懷疑人生了。
作者介紹
宇文湛泉,現(xiàn)任金融行業(yè)核心業(yè)務系統(tǒng)DBA,主要涉及Oracle、DB2、Cassandra等數(shù)據(jù)庫開發(fā)工作。
























