2010-01-20 50 views
7

我們目前正在開發一個Web應用程序,其中一項功能是由用戶創建事件。這些事件可以稍後由用戶或管理員刪除。但是,客戶端要求事件並非真正從數據庫中刪除,而只是標記爲已刪除。用戶只能看到未刪除的事件,但管理員應該也可以通過刪除的瀏覽器進行瀏覽。這就是所有功能。在數據庫中設計檔案。一些模式可能?

現在我建議我們應該簡單地增加一個名爲「狀態」額外的列,這將有幾個有效值:ACTIVE和刪除。通過這種方式,我們可以區分正常(活動)和已刪除事件,並創建真正簡單的查詢(SELECT * FROM EVENTS WHERE STATUS ='ACTIVE')。 但是我的同事不同意。他指出,不管現在活動事件和已刪除事件在將來的需求中是否共享相同的信息(因此它們可以存儲在同一個表中),我的更改和客戶端例如需要存儲一些關於已刪除事件的附加信息(比如刪除日期,刪除它,爲什麼他這麼做 - 有點評論)。他表示,爲了在將來滿足這些要求,我們必須在EVENTS表中添加額外的列,這些列將保存特定於已刪除事件的數據,而不是針對活動事件。他提出了一個解決方案,在該解決方案中創建具有與EVENTS表相同模式的附加表(如DELETED_EVENTS)。每個已刪除的事件都將從EVENTS表中物理刪除並移至DELETED_EVENTS表。

我強烈他的想法不同意。它不僅會使SQL查詢更復雜,效率更低,而且這完全是針對YAGNI的。我也不同意他的觀點,即如果未來需求發生變化,我的想法會使我們在EVENTS表中創建更多(不可爲空)的列。在我的場景中,我會簡單地創建像DELETED_EVENTS_DATA這樣的新表(它將保存這些額外的存檔數據),並在EVENTS表中添加引用鍵以維護EVETNS和DELETED_EVENTS_DATA表之間的一對一關係。

不過我被一個事實,即兩個開發誰在軟件和數據庫設計通常有着相似的看法可能有關於如何要求應該在數據庫級別被設計成完全不同的意見掙扎。我認爲我們可能都走錯了方向,還有另一個(第三個)解決方案?還是有更多的只是一個選擇? 你如何設計這種要求?有沒有適當的方式或指導方針?任何幫助將十分讚賞

+0

您可能會考慮將其標記爲社區維基 - 我不確定您會找到可證實的正確答案。 – Mayo 2010-01-20 22:45:14

+0

這是一個很好的問題,我期待看到一些顯示的答案。複製到DELETED_EVENT表格時從表格中刪除行可能會導致一些問題,如果有任何對您的EVENTS表的引用需要保留以用於歷史目的。你最終會得到懸掛的外鍵,或者你可能必須加入兩個表的外鍵。聽起來不漂亮。 – rayd09 2010-01-20 22:49:40

+0

爲什麼我的回答被解除了答案? – anthonyv 2010-01-21 20:55:39

回答

0

確定我們處理它的方式如下。

我們在每個表上都有一個名爲'Deleted'的額外列,這是一個位字段。然後,您正確地說過,您的查詢非常簡單,因爲它只是一個where子句,可以將它們過濾出來或放入其中。唯一需要確定的是,您生成的任何報告或統計信息會過濾掉已刪除的記錄。

然後,對於您正在討論的想要捕獲的額外信息,只需將這些額外信息放入單獨的「審計」(如表格)中即可。在我們的例子中,我們取得了這額外的表是通用,如果你有你想要捕捉到其他實體它可以容納任何表本次審計信息...見下文它是如何工作...

Event 
EventId EventName ... Deleted 
1   Dinner   0 
2   Supper   1 
3   Lunch    0 
4   Lunch    1 

Audit 
AuditId EntityTypeId  EntityId ActionTypeId ActionDateTime ... etc 
1   1 (Event)  2 (EventId) 1 (Deleted)  2/1/2010 12:00:00 
1   1 (Event)  4 (EventId) 1 (Deleted)  3/1/2010 12:00:00 

現在(像位置 - 位置是一個表),以及它看起來像這樣...

Audit 
AuditId EntityTypeId  EntityId ActionTypeId ActionDateTime ... etc 
1   1 (Event)  2 (EventId) 1 (Deleted)  1/1/2010 12:00:00 
1   1 (Event)  4 (EventId) 1 (Deleted)  2/1/2010 12:00:00 
1   2 (Event)  2 (LocationId) 1 (Deleted)  3/1/2010 12:00:00 
1   2 (Event)  8 (LocationId) 1 (Deleted)  4/1/2010 12:00:00 
1   2 (Event)  9 (LocationId) 1 (Deleted)  5/1/2010 12:00:00 

然後,當你想擺脫你正在談論它相當簡單額外的審計數據。查詢會是這個樣子

SELECT * 
FROM Event E 
     INNER JOIN Audit A 
      ON E.EventId = A.EntityId 
WHERE E.Deleted = 1 
     AND A.EntityTypeId = 1 -- Where 1 stands for events 

而且該審計表可以捕獲其它事件,而不僅僅是刪除......這是通過使用ActionTypeId柱完成。目前它只有1個(這是刪除),但你也可以有其他的。

希望這有助於

編輯:

在此之上,如果我們有強大的審計要求我們做的上述變化如下......沒有,但是我們創建了一個名爲「xyz_Audit」第二個數據庫,捕獲數據庫中發生的每個操作的前置和後置。第二個數據庫具有與第一個數據庫(沒有Audit表)相同的模式,除了每個表都有兩個額外的列。

第一個額外的列是PrePostFlag,第二個列是AuditId。因此主鍵現在跨越3列'xyzId','PrePostFlag'和'AuditId'。

通過這樣做,我們可以讓管理員充分了解誰在什麼時候做什麼,更改了數據以及如何更改數據以及取消刪除記錄,我們只需要更改主數據庫中已刪除的標誌。

此外,通過將這些數據放在不同的數據庫中,它使我們能夠對主跨國數據庫進行不同的優化,存儲和管理計劃。

+0

隨着時間的流逝,這個模式將會變得越來越慢,因爲低值數據將被無限期地保存下來。此外,這將需要在創建報告時檢查標誌,從而消除了分離關注的好處,並根據不應該記錄的邏輯包含邏輯。一種更好的方法,而不是這種「軟刪除」方法將是使用數據庫歸檔方法。 – 2012-03-27 19:43:02

2

我發現,在另一臺拍攝物體的快照與每個事件(創建,更新等),並存儲這些快照(使用日期和用戶信息一起)使您能夠滿足各類的應用程序生命週期中的歷史跟蹤需求。然後,您可以向用戶呈現快照,向用戶呈現時間變化,推斷給定日期的對象狀態等。

我確信有官方設計模式 - 這只是我隨着時間的推移而改進,並且效果很好。但是,它對磁盤空間效率不高。

編輯:另外,當用戶刪除的對象,我會標誌備案爲刪除並承擔歷史表最後的快照。您可以無限期地從界面隱藏對象,或者您可以選擇顯示它 - 取決於使用需求。

+0

我完全同意這個方法。 – NotMe 2010-01-20 22:49:58

+0

爲什麼是快照而不是交易? – 2010-01-22 03:02:36

+0

@calico:我是通過交易來假設你是指存儲的是被改變的而不是狀態?我確定這兩種方法都適用於審計,但快照方法允許您在任何給定的時間輕鬆確定對象的狀態 - 我們已在多個項目中使用了此要求。 – Mayo 2010-01-22 12:41:00

0

這往往是在這樣的情況下一個判斷。除了你告訴我之外,我不知道任何事情,但我會傾向於用你的解決方案,而這只是虛擬刪除。我相信你對YAGNI的應用很好。如果用戶今後確實需要在事件事件中記錄階段的要求,那麼很可能在這個時候你們不會準確地猜出這些要求究竟是什麼。如果在數據庫中處理事件的邏輯已被很好地封裝(稍後易於更改),那麼尤其如此。然而,如果你很瞭解這個客戶,並且你知道他們有類似的歷史類型需求,而且功能不會被很好的封裝,那麼你的同事可能會做出一個很好的猜測。這裏的關鍵是,無論你們哪一個人是正確的,這是不是太多。雙方都有優點。順便說一下,最好有一個布爾型(是/否)IsDeleted列,索引以該列開頭。這將會更快,但它可能不會產生足夠大的差異。

+0

什麼部分的業務邏輯會被「刪除」?爲什麼要將低價值的數據保存在高性能數據庫中? – 2012-03-27 19:44:26

+0

@Travis。有趣的是,downvote。你能否澄清你的意見?第一個我無法理解。至於第二,你認爲OP的客戶想要保存這些數據是錯誤的嗎?因此,我幫助他的嘗試很糟糕,因爲他不應該一開始就這麼做。我應該告訴他,他的客戶想要保留這些數據是錯誤的? – 2012-03-27 20:12:40

+0

您應該告訴他在生產數據庫中保留不推薦使用的數據是錯誤的。 – 2012-03-27 20:13:49

0

我現在要添加標誌字段,只有當你主動知道你將要做什麼時才計劃休息,系統也積累了真實世界的數據和用戶體驗,所以你有一些數據以您的性能/複雜性設計決策爲基礎。

3

請勿使用狀態列。

至少應該有一個datedeleted和一個deletedby列。即使客戶沒有立即要求,他們第一次去看已刪除的事件時,他們會想知道是誰來辨別原因,但僅僅知道被刪除的東西並沒有幫助。

如果事件表的大小可能增長很大,通常會將刪除/存檔的數據完全移到不同的表中。通常你會將這些表分配給不同的數據庫文件。該文件通常位於不同的驅動器上以保持性能。我並不是說一個全新的數據庫,而只是一個不同的數據庫文件。

如果將它保留在同一個表中,則所有查詢都應該有一個where子句(DateDeleted爲null)。顯然,如果信息被移到不同的表格中,你就沒有這個要求。這就是爲什麼我建議這樣做的原因。

+0

我同意,使用另一個數據庫提供了許多明顯的優點,例如不必在查詢中使用邏輯雲,或者使性能db與舊數據混淆。 – 2012-03-27 19:46:11

0

這很大程度上取決於表的大小以及是否真的需要有關刪除的附加信息。

在大多數情況下,刪除標誌字段是您所需要的。然後創建一個視圖,用於選擇記錄未被刪除的記錄。對用戶的所有查詢使用視圖,而不是直接訪問表。

如果您已進行審覈,您已經知道是誰將該記錄標記爲刪除和何時。

如果不是,您應該將這些字段添加到您的表中。

爲了提高主表上的查詢性能,我可能會定期刪除已刪除的記錄到歸檔表。請說出移動所有已刪除超過6個月的已刪除記錄。然後有一個結合了普通表和歸檔表的管理員查看的視圖。

這兩種方法與使用視圖相結合可以讓你兩全其美,你的桌子在查詢時保持非常小,每個人都可以看到他們需要查看的記錄,並且可以輕鬆地取消刪除被刪除的內容事故,將舊記錄存檔可以在一天的低使用時間段發生,而不是在記錄被標記爲刪除時發生。

0

當用戶創建,修改或刪除事件時,請創建一個新的transaction對象。在事務中存儲有關事件更改的所有信息,並將其添加到表中並引用該事件。這樣你就擁有了用戶所做的一切的審計日誌。這增加了最小的複雜性,但也允許擴展。您甚至可以稍後添加撤消功能,並對數據模型進行最小限度的更改(如果有的話)。

因此,如果用戶正在查看日誌,您可以檢索每個日誌,而無需與其關聯的DELETE事務,但管理員可以查看所有內容。

+0

只是爲了澄清:我會使用命令設計模式來實現事務。 – 2010-01-22 03:03:16