1. 程式人生 > 其它 >mysql邏輯刪除真的不是一個好的設計

mysql邏輯刪除真的不是一個好的設計

轉自:https://www.jianshu.com/p/f37281576585

在網際網路公司中資料的積累是非常重要的,所以就有了邏輯刪除這樣的設計。所謂邏輯刪除就是在表中加入類似is_deleted欄位,將刪除操作變成更新操作。當is_deleted=1時就代表這條記錄已經刪除,這樣做的好處非常明顯,資料不會消失,對於商業分析來說“被刪除”的資料也非常有價值。

但事情往往不會這麼簡單,硬幣的另一面是邏輯刪除引入了一點點複雜度,大部分讀操作都需要過濾掉處於刪除狀態的記錄,過濾操作要麼在資料庫層面完成,要麼在應用中完成,通常這樣的複雜度是完全可以接受的,但是對於MySQL而言,邏輯刪除的設計還會導致常用的unique key失效,原因非常簡單,已經刪除的資料仍然存在,所以在設計unique key的時候程式設計師不得不將is_deleted欄位與應用要求unique的欄位一起放入unique key中,這樣is_deleted=0的記錄就不會與is_deleted=1的欄位衝突了,這是符合邏輯的,is_deleted=0的記錄之間會發生衝突,但這正是unique key的本意,所以也是符合邏輯的,但是問題在於is_deleted=1的記錄之間也會發生衝突,這可能就不符合邏輯了,為什麼呢?簡單來說這樣的設計在unique key存在的情況下不允許unique key欄位相同的記錄被刪除兩次以上,這對於應用來說是一個很大的限制。

而實際上很多網際網路公司在資料庫設計規範中都加入了邏輯刪除的強制規定,從商業分析的角度來說這樣做沒有問題,但問題留給了開發人員,我們只能在unique key與邏輯刪除之間做一個排他的選擇嗎?但是unique key都放棄了,我們用的還是關係型資料庫嗎?不過兩者都兼得的辦法還是有的,我個人認為有三種方案,依次是1不靠譜方案,2靠譜方案,3推薦方案

1. 不靠譜方案:放棄使用MySQL

朋友們,看完這個小標題你完全可以選擇跳過這一段。
但為什麼說這樣可以解決問題呢,因為我們需要的其實是這樣一個功能:unique key where is_deleted=0,對嗎?我們其實不關心is_deleted=1的記錄是否重複,遺憾的是MySQL並不支援這個功能,但是並非所有的資料庫都不支援這個功能,比如SQL Server就可以。

2. 靠譜方案:增加delete_token欄位

是的,除了is_deleted欄位我們還需要增加一個delete_token欄位來完成邏輯刪除這個設計。定義的方式是這樣的,delete_token varchar(32) not null default 'NA',使用方式是:首先is_deleted欄位不再參與unique key,而是將delete_token加入unique key中,在刪除時,is_deleted欄位更新成1,同時delete_token欄位更新成一個32位的uuid,這樣刪除的記錄因為uuid的存在就不會衝突了,問題解決了。但為什麼我不推薦使用這個方案呢?因為MySQL對於unique key的長度是有限制的,對於InnoDB來說這個限制是767 bytes, 對於MyISAM這個限制是1000 bytes,假設你使用了utf8mb4 字元編碼,那麼delete_token就會佔據128 bytes,這其實引入了另一個隱含的限制。

3. 推薦方案: 使用資料倉庫

回到邏輯刪除的初衷,我們需要的是將資料沉澱下來用於商業分析,而邏輯刪除的設計將資料分析與應用邏輯雜糅在了一起,而實際上應用使用的MySQL並不適合做資料分析,又平白增加了應用的複雜度,這樣的設計最終兩頭都不討好。所以還是讓應用資料庫與資料倉庫發揮各自的功能吧,應用資料庫與資料倉庫都可以通過監聽資料操作指令來自由的更新資料,至於刪除操作,對於應用資料庫來說就是物理刪除,但對於資料倉庫來說可以只是一條更新操作。

總結:

為什麼我們要使用MySQL這樣的資料庫呢?因為我們關心的不止是資料本身還有資料之間的關係,而MySQL的這樣的資料庫天生就是為這些關係設計的,從目前來說這些關係當中並不包含刪除關係。