為什么我會看到這篇文章?
你可能是一個程序員,在簡書的搜索框上輸入了“數(shù)據(jù)庫邏輯刪除解決方案”并點擊了搜索按鈕源请。
- 本文章有很多廢話绢涡,如果不想看直接拉到底部 -
我遇到什么問題了?
在進行數(shù)據(jù)庫設(shè)計時,你的公司認為數(shù)據(jù)對于公司來說存在重大意義(即便是已經(jīng)刪除的數(shù)據(jù))呕缭,因此你被強制要求對于數(shù)據(jù)的刪除只能使用邏輯刪除,即增加一個標記字段來記錄該數(shù)據(jù)的刪除狀態(tài)。
你遇到了這樣一個場景瘟判,你的某個字段需要添加唯一鍵約束怨绣,因此你可能想了個辦法,用業(yè)務來控制唯一鍵拷获。例如你的數(shù)據(jù)表中name是唯一的梨熙,現(xiàn)在你需要插入一條name = a的記錄:
然而你的服務運行了一段時間后你還是發(fā)現(xiàn)了數(shù)據(jù)庫中存在 name = a 且 is_delete = 0 的多條字段,大部分是由于以下原因:
你發(fā)現(xiàn)在業(yè)務層面這個問題似乎是無法避免的刀诬,于是你開始考慮從數(shù)據(jù)庫層面避免該問題咽扇。你決定在name字段添加唯一鍵約束,但很快就否定了這個想法陕壹,因為這樣根本沒法進行刪除质欲,所以你開始在網(wǎng)上尋找解決辦法。
有沒有解決這個問題的辦法糠馆?
百度嘶伟、谷歌幫幫我。
在網(wǎng)上搜尋很久以后又碌,我看到了簡書上一篇比較好的文章:邏輯刪除真的不是一個好的設(shè)計九昧。該文章提供了三個方法: 1.放棄mysql? 2.添加delete_token字段? 3.使用數(shù)據(jù)倉庫,評論區(qū)機智網(wǎng)友還提出了方法2的改進: 方法2.5毕匀。
方法2铸鹰,即為數(shù)據(jù)庫添加新的一列delete_token,當某一條記錄需要刪除時皂岔,將該字段設(shè)置為一個UUID蹋笼,將name、delete_token設(shè)置為唯一鍵躁垛,這樣當is_delete=0時剖毯,delete_token保持一個默認值,能夠有效地限制name唯一教馆,當記錄被刪除時逊谋,由于delete_token是一個唯一的UUID,便能保證刪除的記錄不會被唯一約束束縛土铺。但正如該文章的博主所說胶滋,UUID會占用很大的空間,所以不推薦使用舒憾。評論網(wǎng)友針對該問題提出優(yōu)化對策:方法2.5:將刪除記錄的delete_token設(shè)置為該記錄的id镀钓。
個人認為,索引太大只是其中一個弊端镀迂,該方法還會面臨一個很棘手的問題:當需要批量刪除時丁溅,需要對每一條記錄進行逐行刪除。例如該表還有一個字段叫age探遵,現(xiàn)在需要刪除age > 18的記錄窟赏,共有50條妓柜,在業(yè)務中,由于需要為每條的delete_token字段插入一個UUID所以需要將其拆分為50條更新操作來進行涯穷。這樣的代價顯然很難接受
我該怎么辦棍掐?
每種辦法都有一定的應用場景,既然強制要求使用邏輯刪除拷况,就會面臨很多問題作煌,在所難免。今天剛好突然想到一個不錯的點子能解決邏輯刪除帶來的問題赚瘦,若該方法已經(jīng)被提出粟誓,純屬巧合。
將刪除標記設(shè)置默認值(例如0)起意,將唯一字段與刪除標記添加唯一鍵約束鹰服。當某一記錄需要刪除時,將刪除標記置為NULL揽咕。
由于NULL不會和其他字段有組合唯一鍵的效果悲酷,所以當記錄被刪除時(刪除標記被置為NULL時),解除了唯一鍵的約束亲善。此外該方法能很好地解決批量刪除的問題(只要置為NULL就完事了)设易,消耗的空間也并不多(1位 + 聯(lián)合索引)。
目前還沒發(fā)現(xiàn)這個辦法有什么奇怪的bug逗爹。如果有請不要吝嗇在評論區(qū)留言討論亡嫌。