資料庫中計算值的更新方法

2021-09-06 08:43:53 字數 1775 閱讀 6216

在做專案時,經常在專案中會遇到有些值是通過其他表經過計算得來的,然後將計算結果儲存到資料庫中。比如在乙個休假系統中,乙個員工每年已休天數就是乙個計算值,通過sum員工的所有有效休假申請單可獲得。再比如交易系統中的餘額字段,對乙個賬號的所有流水進行sum,所有收入減去所有支出就是餘額。再比訂單系統中,訂單的總金額字段,就是訂單明細的金額的sum值。

對於這些字段,都有乙個共性,那就是這個欄位是可以通過其他表的字段計算出來的,可以認為這個欄位是冗餘的,如果沒有這個字段,那麼我們的系統仍然可以設計出來並且功能乙個都不會少。這個字段主要為了提高查詢的效能,出報表時也方便,效率高。

既然是乙個冗餘字段,那麼就需要在更新資料時,及時更新這個字段,這裡就涉及到乙個問題,怎麼更新呢?一般我們採用兩種方法進行更新。

1.基於現有的計算值,在更新相關資料時加減該計算值。

在需要計算的資料量比較大的情況下一般採用這種方法。比如交易系統中,乙個賬戶會產生大量的交易流水,而且隨著時間的增長,流水會越來越多,那麼在每次交易時直接用餘額加減本次交易的金額即可得到新的餘額,這種計算速度會很快。

2.每次更新相關資料時,根據所有資料重新計算。

在計算量較小是使用這種方法。比如我們的訂單系統中,訂單的總金額就是彙總訂單明細的金額,如果刪除了或者增加了訂單明細,那麼只需要重新彙總即可。由於乙個訂單的明細一般不可能很多,而且隨著時間的增長,乙個訂單明細也不可能越來越多。所以每次修改訂單,重新計算總金額也不會太多的占用cpu資源。

那麼我們再來看一看前面提到的休假系統是採用哪種方式計算員工的已休年假天數呢?首先員工的休假單並不會很多,乙個員工一年頂多也就請幾十次假,不可能一年請個幾千幾萬次假。其次,休假天數是按年劃分的,不需要按照員工的所有休假記錄進行彙總,所有計算量也不會隨著時間的增長而增長。從這2點來看,那麼休假系統的已休年假天數應該用第二種方式,每次休假申請時重新計算已休天數。

使用第一種方法,計算量小,速度快,但是如果資料一旦發生異常,那麼以後的計算就會將錯就錯,一直錯下去。

第二種方法在每次更新資料時重新計算,需要一定的計算量,所以不能用於大資料量的計算,優點是不用擔心資料不一致的問題,保證計算列是正確的。

如果使用第一種方法,如何避免資料不一致呢。乙個常用的方法是建立乙個定時任務,在資料庫閒時使用全量資料重新計算每天發生更改的資料的計算值,然後用這個值和資料庫中的該列進行比較,如果不相同,那麼就通知管理員,人為清查資料不一致的原因,將資料修復。

另外在使用第一種方法的時候,一定要注意併發問題。比如乙個銀行系統,如果我們要取錢,那麼這個操作會對應資料庫的這樣操作:

1.開啟乙個事務。

2.select讀取餘額,判斷是否有足夠餘額用於支取。

3.insert,記錄取錢這個流水。

4.update賬戶的餘額字段:新的餘額=步驟1讀取的餘額-取錢金額。

5.提交事務。

如果使用者有100元的餘額,現在同時發起2個取100元的操作,那麼按以上操作,在操作2時都是讀取到100元,都可以取錢,然後會造成記錄了2條取100的流水,但是餘額卻是0的情況。如果我們採用的是餘額通過流水進行重新計算的方法:

4.update賬戶的餘額字段:新的餘額=sum(流水)。

那麼同時發起2個取100元操作的話,兩個事務都會執行到步驟3,事務1可以執行步驟4,但事務2由於需要讀取流水表,該錶被事務1的的步驟3所lock了,所以事務2等待事務1完成。最後事務1提交成功,餘額變為0,然後事務2執行步驟4,餘額變成-100,違反約束,導致事務2回滾,取錢失敗。

當然並不是說採用方法1就沒辦法避免併發問題。可以在步驟2時將共享鎖上公升為獨佔鎖(select for update),那麼就不會造成資料錯誤。

資料庫字典簡易更新方法

公司現在使用的資料庫都是 sql,軟體在開發的過程中的資料庫的設計會有著很多的變化 這就帶來了很多的更新繁瑣的工作 以至公司的軟體的資料庫的文件得到不及時的更新 勢必影響著相關的一系列的工作的執行。在這邊結合了去年工作的實踐,提出一種比較方便的資料庫更新與資料庫文件同步的方法,這個方法的原理也很簡單...

cocoapods本地的類庫更新方法

cocoapods裡管理的第三方更新的非常頻繁,可能每個小時裡面就會有一大堆的更新,所以,如果我們想使用最新的第三方我們就需要養成經常更新本地的類庫的習慣,而且如果我們不時常更新的話,當我們某一天集中更新的話,會耗費較長的時間.所以養成這種習慣也挺好,更新本地類庫很簡單,並不需要很多步,但有可能很耗...

Access資料庫的多表更新方法和列變行一例

1 access資料庫的多表更新方法 x update dltb a inner join tbarea2 b on a.objectid b.fid set a.fd dltb xzdwmj b.area xzdw,a.fd dltb lxdwmj b.area lxdw sqllist.add ...