在企業資料庫設計中,經常會遇到乙個需求,就是希望把操作之前的資料保留下來,能夠看到操作之前是什麼資料,操作之後是什麼資料。對於這種需求,我們可以使用保留歷史資料或者使用版本來實現。
為了能夠保留歷史資料,在版本設計時有以下方案:
一、使用版本號
版本號是一種常見的版本設計方案,就是在要進行歷史資料保留的表上面增加乙個版本號字段,該欄位可以是datetime型別,也可以是int型別,每進行資料操作時,都是建立乙個新的版本,版本是只增不減的,所以只需要拿到最大乙個版本號,就能得到最新的業務資料。
版本號除了能夠用於留存歷史資料外,還有乙個功能就是避免併發編輯操作。比如我們有乙個物件a,當前的版本是1,兩個使用者同時開啟了該物件的編輯頁面,進行資料更改。先是甲使用者提交更改,這個時候系統把物件的id和版本進行查詢,發現要修改的資料最新版本是1,所以成功修改,儲存了物件a的新版本2。這個時候使用者乙也提交了修改。系統把物件的id和版本1進行查詢,發現要修改的資料最新版本是2,不符合要求,所以拒絕使用者乙的修改。使用者乙只有重新整理介面,拿到最新的版本2,再進行修改。
id單號
金額版本號
1exp123
1001
在使用版本號的情況下,對單據的金額進行修改,修改後建立新的版本號2:
id單號
金額版本號
1exp123
1001
2exp123
1202
二、使用生效、失效時間
儲存歷史資料的第二辦法是使用生效失效時間來表示乙個版本。要進行歷史資料記錄的表增加「生效時間」「失效時間」兩個字段,兩個欄位不允許為空。對於剛建立的資料,生效時間是建立該資料的時間,失效時間是9999-12-31。現在對這條資料進行了修改,那麼我們只需要將當前時間設定為上乙個版本的失效時間,同時建立一條新資料,生效時間是當前時間,失效時間是9999-12-31即可。
id單號
金額生效時間
失效時間
1exp123
1002013/9/1 15:30:00
9999/12/31 23:59:59
比如上面一條單據,是2013-9-1建立的,後來在2013-9-9 15:00:00對該單據進行修改,將金額從100修改為120,儲存時建立的新資料如下:
id單號
金額生效時間
失效時間
1exp123
1002013/9/1 15:30:00
2013/9/9 15:00:00
2exp123
1202013/9/9 15:00:009999/12/31 23:59:59
使用了生效、失效時間後,我們可以查詢任意時刻資料庫中資料的值,只需要把要查詢的時刻傳入,然後between 生效時間 and 失效時間即可。
使用前兩種方案都需要乙個業務主鍵來標識具體的乙個業務資料。如果我們要記錄的實體沒有明確的「單號」、「訂單號」這類的業務主鍵該怎麼辦?我們可以使用建立資料時的資料庫主鍵作為業務主鍵。
員工id
姓名生日
業務id
版本號1
張三1984/12/2911
比如我們有個員工表,記錄員工基本資訊,在建立張三這個員工的資料時,其在資料庫的id為1,那麼可以將其業務id也設定為1。接下來對張三的屬性進行更改,記錄了版本,那麼就會建立新的版本,其主鍵「員工id」會變化,但是其業務主鍵「業務id」始終是1,不會變化的。
員工id
姓名生日
業務id
版本號1
張三1984/12/2911
2張三1985/1/912
使用前面兩個方案雖然能夠很好的記錄歷史資料,但是每次修改資料都會導致新版本生成儲存,所以每個版本的id都是新的,所以必須有乙個業務主鍵來標識乙個實體,這裡的兩個例子「單號」就是其業務主鍵。主鍵的變動使得所有關聯的物件都得變動,從而形成連鎖效應,使得各個關聯的物件也生成新的版本。比如我們有個訂單系統,裡面有訂單表和訂單明細表。現在我們要對訂單的修改記錄歷史版本,所以增加了生效時間和實效時間,並使用訂單號作為業務主鍵。現在有乙個訂單a,下面有100條明細,如果要對訂單進行修改,將某一條明細的屬性進行修改,從而導致整個訂單的變化,那麼我們就需要建立新的訂單資料行,由於主鍵變動,所以訂單明細都需要變動,所以100條明細都需要建立新的版本,新版本的訂單明細中,「訂單id」指向了新的版本的訂單資料的id。
這樣的設計造成的問題就是訂單明細表會極速膨脹,如果乙個訂單有1000條明細,我們只是修改了訂單本身的屬性,並不修改訂單明細,也會造成對這1000條明細做copy,然後儲存。那怎麼辦呢?我們可以使用以下辦法:
1.對訂單明細建立版本字段,將版本的粒度細化到訂單明細,而不是訂單。訂單與訂單明細不存在資料庫級的外來鍵關係,只存在業務級的外來鍵關係。也就是說訂單明細表中增加生效時間、失效時間之外,還需要增加「訂單號」這個字段,用於表名該明細是屬於哪個訂單的。
我們這麼修改後,如果訂單物件進行了修改,訂單明細沒有修改(比如改了一下收件人資訊),那麼只需要在訂單表中生成新的一行資料,訂單明細不會copy生成新的資料。如果我們對某一條訂單明細進行了更改(比調整了單價、數量)那麼只需要對具體修改的那條訂單明細進行更改,而不需要對整個訂單的所有明細進行更改。
使用這種設計後,查詢訂單及其明細,需要對兩個表執行生效失效時間的過濾,而且明細的獲取是通過訂單號去取,而不是通過訂單id去取。
將版本控制的粒度細化到訂單明細時,後台程式的邏輯也會更加複雜。使用者在介面上操作的是訂單物件,系統會將整個修改後的訂單物件傳到後台,後台程式需要對每個訂單項進行對比,如果發現訂單項進行了修改,那麼就會呼叫生成新版本訂單明細的方法。
2.使用單獨的歷史表
這是另外一種實現歷史版本記錄的方法:
三、使用單獨的歷史表
使用歷史表其實就是建立完全相同schema的表(當然,也可以新增更多的字段用於記錄額外的歷史版本資訊),該錶只保留歷史版本的資料。這有點像乙個歸檔邏輯,所有歷史版本我們認為都應該是不經常訪問的,所有可以扔到單獨的表,對於現有生效的版本,仍然保留在原表中,如果需要查詢歷史版本,那麼就從歷史表中查詢。
使用單獨的歷史表有以下好處:
使用歷史表記錄歷史版本主要是要對資料操作方法(增加、刪除、修改)進行修改,使得每次資料操作時,先在歷史表中留痕,然後再進行資料操作。另外就是對查詢歷史版本功能進行修改,因為歷史資料在另外乙個表中,所以對於的sql是不一樣的。當然,我們也可以建立歷史版本資料庫,裡面儲存了所有的歷史表。
資料庫模型設計 歷史表與版本號設計
在企業資料庫設計中,經常會遇到乙個需求,就是希望把操作之前的資料保留下來,能夠看到操作之前是什麼資料,操作之後是什麼資料。對於這種需求,我們可以使用保留歷史資料或者使用版本來實現。為了能夠保留歷史資料,在版本設計時有以下方案 一 使用版本號 版本號是一種常見的版本設計方案,就是在要進行歷史資料保留的...
資料庫模型設計 表設計
曾經何時,發現自己設計的表,根本不滿足業務發展。1.業務id的設計,如商品表,單錶就不說了,在如今海量資料的背景下,當然要分庫發表啦。商品表,id,item id,表位置,id當然就是主鍵了,在單錶情況下,保持唯一就可以。item id商品id,就是要在全域性保持唯一,可能商品表有30張,甚至100...
設計資料庫ER模型
最近在作報告的時候,經理說需要畫er圖。對於我這個不是科班出身的同學,畫er圖還真沒做過。er圖確實聽說過,大概也知道用來做什麼,但具體是什麼樣子就不得而知了。於是在google開始搜尋。構成e r圖的基本要素是實體型 屬性和聯絡,其表示方法為 實體型 entity 具有相同屬性的實體具有相同的特徵...