大家好,我是架構擺渡人。這是實踐經驗系列的第六篇文章,這個系列會給大家分享很多在實際工作中有用的經驗,如果有收穫,還請分享給更多的朋友。
不知道大家有沒有遇到過類似的問題,每次新需求上線,或多或少都會有表結構的變更。主要就是需要新增欄位來儲存某些特有需求的資料,聽起來其實很正常,新需求嘛,加欄位,加表都是正常的,如果是傳統行業也沒啥太大問題。但是對於網際網路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方式也不能解決搜尋的問題,一般這種附加資訊的儲存也是不會有搜尋的需求,否則也不適合這種儲存方式。