簡(jiǎn)介眾所周知,對(duì)于海量數(shù)據(jù)的schema修改是一個(gè)極其昂貴的代價(jià),MySQL分表的很大原因其實(shí)就有500w數(shù)據(jù)一個(gè)表,DDL會(huì)比較快。 一般來(lái)說(shuō),動(dòng)態(tài)schema是指的非固定表結(jié)構(gòu),schema字段(有時(shí)也指索引)的增刪對(duì)于正常的讀寫(xiě)沒(méi)有任何影響。一般有兩個(gè)方向的表現(xiàn)形式:
NoSQL中一般采用后者,而關(guān)系型數(shù)據(jù)庫(kù)可能會(huì)采用前者,兩者的區(qū)別是,前者雖然是固定表結(jié)構(gòu),但是可以通過(guò)一定的方式進(jìn)行在線修改,同時(shí)盡可能不影響服務(wù),而后者是原生支持動(dòng)態(tài)schema,是很多NoSQL產(chǎn)品所支持的feature之一,也是它們之于開(kāi)源關(guān)系型數(shù)據(jù)庫(kù)的優(yōu)勢(shì)所在。下面我將就目前比較通用的動(dòng)態(tài)schema解決方案就一一介紹。 OSCOSC即Online Schema Change,是Facebook出的一個(gè)在線修改Schema的PHP腳本,它解決了MySQL長(zhǎng)期以來(lái)無(wú)法在線進(jìn)行Schema變更的一大難題,也成功將Facebook曾經(jīng)添加一個(gè)索引需要幾個(gè)月的滾動(dòng)升級(jí),變成了現(xiàn)在的幾天。 OSC目前包含以下幾個(gè)步驟:
看到這個(gè)步驟,或許很多人都覺(jué)得簡(jiǎn)單,其實(shí)實(shí)踐過(guò)程還是比較復(fù)雜的,有興趣的人可以去看看,這里不做過(guò)多介紹。 http://www./notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932 總之,對(duì)于關(guān)系型數(shù)據(jù)庫(kù)來(lái)說(shuō)一般都是采用的Online Schema Change這種解決方案,商業(yè)數(shù)據(jù)庫(kù)Oracle和DB2都有比較和諧的Online Schema Change解決方案,但是考慮到其成本,這里不做過(guò)多介紹了。
優(yōu)點(diǎn):在線變更,無(wú)額外空間消耗
Schema-free一般來(lái)說(shuō),文檔數(shù)據(jù)庫(kù)(Document-orient Database)支持Schema-Free,就mongodb來(lái)說(shuō),它的一行記錄可能是以下格式:
嚴(yán)格來(lái)說(shuō)其實(shí)就是JSON,不過(guò)mongo采用的是BSON二進(jìn)制編碼,因此空間上來(lái)說(shuō)應(yīng)該會(huì)比JSON省一些的。 因此,對(duì)于這種類(lèi)型的動(dòng)態(tài)schema方式來(lái)說(shuō),實(shí)際是使用key/value存儲(chǔ)的,一條記錄的多個(gè)字段實(shí)際是用json方式合并存在value中。解析的時(shí)候按照J(rèn)SON解析即可,不好的地方是有額外的空間消耗,也許有點(diǎn)人覺(jué)得把字段名取為一個(gè)字母,但是這樣可讀性就太差了。
優(yōu)點(diǎn):完全的schema-free,無(wú)需任何改變,適用于及其復(fù)雜多變的業(yè)務(wù)。
Any More?這里補(bǔ)充一點(diǎn),看到有朋友對(duì)于此實(shí)現(xiàn)有疑問(wèn),這里所說(shuō)的schema-less是針對(duì)的key-value存儲(chǔ),不針對(duì)mysql數(shù)據(jù)庫(kù), MySQL還是建議使用OSC。
看完前面的兩種解決方案,很多人或許就會(huì)覺(jué)得,是不是NoSQL鼓吹的動(dòng)態(tài)Schema就是一個(gè)笑話呢?把字段存到數(shù)據(jù)庫(kù)里面,誰(shuí)都可以做啊,其實(shí)不然,讓我們看看另外一個(gè)解決方案。這個(gè)方案好不好,大家看完后評(píng)價(jià)。 舉例說(shuō)明,對(duì)于下面一個(gè)Schema:
我們對(duì)于這樣一個(gè)Schema,其元數(shù)據(jù)信息應(yīng)該是什么樣的呢? 首先對(duì)于我們的元數(shù)據(jù)做如下定義:
這里的這個(gè)元數(shù)據(jù)信息是對(duì)于某一個(gè)schema來(lái)說(shuō)的,依次是一個(gè)SchemaId,然后是Name(可以理解為表名),然后是當(dāng)前schema的代數(shù),其實(shí)就是一個(gè)類(lèi)似于版本的東西,初始為0,最后一個(gè)是創(chuàng)建或修改時(shí)間,還有一些其它信息,這里省略掉。 下面是對(duì)于字段的一些元數(shù)據(jù),兩者通過(guò)SchemaId關(guān)聯(lián),包含了所對(duì)應(yīng)的Schema,在schema中的順序(解析的時(shí)候用),類(lèi)型,是否為空,是否為主鍵啊之類(lèi)的。
我們有了這些元數(shù)據(jù)信息以后可以做什么呢? 對(duì)于我們的一行記錄,我們理解為一串二進(jìn)制字節(jié)碼,如何從這串字節(jié)碼中解析我們的字段呢,依靠的就是這些元數(shù)據(jù),下面我將物理上存儲(chǔ)的格式貼出來(lái),大家就明白了:
大家注意看,物理上我們存儲(chǔ)了一個(gè)Generation字段來(lái)標(biāo)識(shí)當(dāng)前的Schema是屬于該schema的哪個(gè)特點(diǎn)的版本。那么根據(jù)這個(gè)Generation以及這個(gè)表名(即StoreName)我們就可以得出一個(gè)SchemaId,根據(jù)這個(gè)SchemaId我們可以得到有序的該Schema的所有字段,那么剩下的就很easy了,如果對(duì)于二進(jìn)制編碼不太熟悉的,請(qǐng)看看Protocol Buffer
好了,那么我們?nèi)绻朐黾右粋€(gè)字段呢?需要做的僅僅是修改元信息,將新的Schema信息存入上面兩個(gè)元數(shù)據(jù),如果想讀取原有的老數(shù)據(jù),那么根據(jù)generation進(jìn)行相關(guān)解析即可,如果插入新的Schema的數(shù)據(jù),使用最新的generation就可以了,一切都非常完美。這個(gè)generation字段還可以使用壓縮編碼的方式,在generation小于128的時(shí)候,我們只需要1個(gè)字節(jié)的額外空間消耗
優(yōu)點(diǎn):無(wú)需額外空間消耗,無(wú)需在線修改,透明的使用,幾乎無(wú)downtime 缺點(diǎn):如果增加字段,原有老數(shù)據(jù)的格式仍然是默認(rèn)值,但我想這一點(diǎn)大部分人都可以將其忽略
總結(jié)上面基本上是目前動(dòng)態(tài)schema的主要實(shí)現(xiàn)方法,如果大家有新的解決方案,請(qǐng)告訴我。 歡迎大家交流討論。 |
|
|
來(lái)自: 博雅書(shū)屋lhs > 《數(shù)據(jù)庫(kù)》