大家好,我是架構擺渡人。這是實踐經驗系列的第六篇文章,這個系列會給大家分享很多在實際工作中有用的經驗,如果有收獲,還請分享給更多的朋友。
不知道大家有沒有遇到過類似的問題,每次新需求上線,或多或少都會有表結構的變更。主要就是需要新增字段來存儲某些特有需求的數據,聽起來其實很正常,新需求嘛,加字段,加表都是正常的,如果是傳統行業也沒啥太大問題。但是對於互聯網To C的應用來說,流量高,數據量大,每次對表進行DDL操作耗時都會非常長,主要是數據量太大了,而且都是分庫分表的,幾千張表都很正常。
用過MongoDB的都有一個很好的體驗就是不用再為加字段煩惱了,因為它沒有這個限制,每一條的數據格式都可以不一樣,也就避免的加字段帶來的煩惱,當然凡事有利也有弊,沒有限制也就意味着出錯的幾率會增加,你永遠不知道讀取出來的數據是什么格式。
通常我們為了盡量避免對現有的表結構進行加字段,都會有一些比較常用的方式來解決這個問題,下面就給大家介紹一些常用的方式。
預留擴展字段
預留擴展字段指的就是在創建表的時候,先預留幾個字段。如果后面需要使用直接就可以用了,也就是提前占個位子的意思。
CREATE TABLE `t_order` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`orderNo` varchar(64) DEFAULT NULL,
`buyerId` bigint(11) DEFAULT NULL,
`storeId` bigint(11) DEFAULT NULL,
`addition1` varchar(64) DEFAULT NULL COMMENT '擴展字段',
`addition2` varchar(64) DEFAULT NULL COMMENT '擴展字段',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
當然這個也不是能夠處理所有情況,主要是你無法確定下一次需求到底需要加什么字段。比如你預留了一個varchar類型和一個int類型,如果后續需求都是要varchar類型的字段,那么int類型的將不能被使用。
存儲Json字符串
在建表的時候會設計一個比較長的字符串字段,比如叫addition。這個里面存儲格式就不再是某一個值了,而是一個Json字符串。這個就有點像Mongodb的感覺了,這樣的好處在於后續有需要要新增字段的就直接可以往里面放即可。
需要注意的是,什么類型的字段可以放在這個addition里面?就是只用於存儲和展示的,不用於條件查詢的數據,因為在Mysql 5.7之前是不支持Json類型字段的,存儲的就是一個普通的字符串而已。但是在5.7之后已經支持了Json類型的字段,這個時候里面的字段是支持查詢操作的。
擴展字段確實能夠解決大部分需求場景,但是問題在於隨着時間的推移,這個字段會越來越大。另一個問題就是當我的需求其實只需要讀取里面的某個值時,沒辦法做到部分讀取,只能全部讀取出來,然后轉成對象,取某個值,其實是比較耗時的。
比如訂單里面存儲了下單時的商品信息和用戶地址信息,如下:
addition={"sku":{name:"xxx",id:111},"addr":{"name":"xxx","city":"xxx"}}
當你要取商品信息的時候,沒辦法單獨讀取。
通用KV服務
最后介紹一個既比較通用又能支持無限存儲的方式,就是單獨實現一個KV服務來支持這種需求。
對於KV服務,核心接口無非就是下面幾個:
- set(key, value)
- batchSet(List<key,value>)
- get(key)
- list(key1, key2,keyn)
底層存儲你可以使用任何數據庫進行存儲,用MongoDB,MySQL都可以。有了KV服務,就可以將addition里面的內容進行拆分,一個key對應一個value進行存儲,讀取也支持多個key或者單個key,按需讀取。
以上面訂單的需求來說,我們就可以將商品信息和用戶信息拆開存儲:
key=訂單號+sku
value={name:"xxx",id:111}
key=訂單號+addr
value={"name":"xxx","city":"xxx"}
當然這種通用的KV方式也不能解決搜索的問題,一般這種附加信息的存儲也是不會有搜索的需求,否則也不適合這種存儲方式。