相信很多人都聽過刪庫跑路
這個詞,用搜索引擎檢索刪庫跑路
,可以看到很多程序員刪庫跑路的討論和新聞。
但是,嚴格來講,大部分程序員想刪庫跑路
也做不到。為什么呢?因為沒有數據庫的刪除權限。——真正能刪庫跑路
的是運維,再准確點DBA。
那么平時業務中的刪除是怎么做的呢?答案是邏輯刪除
。
邏輯刪除:又名軟刪除,與物理刪除、硬刪除相對應,含義是並沒有實際的刪除數據,只是將數據標記已刪除
(例如增加is_deleted字段)。
為什么要用邏輯刪除?
物理刪除
很好理解,就是真的把數據給刪了。
以MySQL為例,假如數據刪了,應該怎么恢復呢?主要方式有兩種。
利用 binlog 日志
binlog是記錄所有數據庫表結構變更(例如CREATE、ALTER TABLE…)以及表數據修改(INSERT、UPDATE、DELETE…)的二進制日志。
使用binlog恢復數據,本質上就是通過binlog找到所有DML操作,去掉錯誤的SQL語句,然后執行其它的SQL語句,就可以將數據恢復。
binlog恢復數據示意圖如下:
可以看到,恢復時候不僅需要停掉數據庫,假如數據量大的話,去篩選恢復數據sql就😂
數據庫延時同步節點
- 給數據庫配置一個同步數據的數據庫
- 同步時間,要延時:比如 1 小時同步一次
- 當出現問題的時候,只要在這個延時時間內,都還可以恢復出一定的數據
所以,綜上,可以認識到,數據刪除之后的恢復是要付出很大代價的,而且還存在不可恢復的風險。所以出於安全考慮,生產環境數據庫應當盡可能禁止物理刪除
。
邏輯刪除會帶來什么問題?
數據冗余
這個不用說,數據沒有實際刪除,自然會產生大量的對業務無用的冗余數據。
增加開發復雜度
寫sql進行數據處理時需要排除那些已經邏輯刪除的數據,這就會導致sql復雜,容易出錯,特別是涉及多表查詢時。
例如:
select t1.name,t2.category from product t1
left join category t2 on t1.category_id=t2.id
where
t1.is_deleted=1
and t1.is_deleted=1
影響惟一性約束
如果數據表的某個字段要求唯一,並強制約束,比如用戶表中的登錄用戶名字段,設計為邏輯刪除的話,一旦有新的同用戶名記錄就無法插入。但如果不將該字段設置為唯一性約束的,那么在每次插入數據的時候,都需先進行一次查詢,看看有無未(邏輯)刪除的同名記錄存在。
如何設計邏輯刪除?
首先需要在表里設計一個刪除的標志字段is_deleted
。
插入數據數據時,這個值默認為0。刪除數據時將這個值設置為1。查詢和更新數據時都將‘deleted=0’這個條件帶上,只查詢和更新沒有刪除的數據。
是不是很簡單?但別忘了我們上面提到的影響惟一性約束的問題。這個該怎么解決呢?
可以將唯一約束字段和刪除相關的字段創建成組合唯一索引:
-
將刪除標記設置默認值(例如0),將唯一字段與刪除標記添加唯一鍵約束。當某一記錄需要刪除時,將刪除標記置為NULL。
由於NULL不會和其他字段有組合唯一鍵的效果,所以當記錄被刪除時(刪除標記被置為NULL時),解除了唯一鍵的約束。此外該方法能很好地解決批量刪除的問題(只要置為NULL就完事了),消耗的空間也並不多(1位 + 聯合索引)。
-
NULL在某些情況下是存在一些問題的,刪除時可以將刪除標記更新為主鍵,這樣同樣保證了唯一約束字段和刪除標記組合索引的唯一性。
-
還可以用另外一種方案,添加一個刪除時間
delete_time
的字段,設置一個不為NULLl的默認值,和惟一字段組成聯合唯一索引,當進行邏輯刪除的時候同時要更新delete_time
,這樣同樣可以保證惟一性。
如果是Java語言開發,推薦MyBatis Plus框架,提供了比較好的邏輯刪除支持。
應該用邏輯刪除嗎?
到現在我們認識到,邏輯刪除有利好之處,但是也要付出一定的代價。那么應該用邏輯刪除嗎?
-
從項目的規模來講
-
一般的建議是小型系統可以采用
物理刪除
,因為數據恢復的成本,或者說數據的價值,相比較使用邏輯刪除
的開發、運維付出要少。但是物理刪除
!=隨意刪除
,要認識到刪除操作的風險,重要數據應該設計歷史表,刪除之前將刪除的數據復制到歷史表。 -
中大型項目應該采用
邏輯刪除
,有一句話“數據是無價的”。必須承認,在很多時候,數據的價值是遠遠高於人工的成本的。
-
-
從數據價值來講
-
價值比較高的數據,如電商系統的訂單之類的,毫無疑問,一般都是只允許
邏輯刪除
的,及時必須要做物理刪除
,也要通過備份表、備份日志等方式保證數據可以快速恢復。 -
價值比較低的數據,比如用戶操作日志之類,這種數據價值不高,而且數據量很大,在資源有限的情況下,可以考慮
物理刪除
,但是這種危險操作盡量也不要由系統功能去做,而應該由專業的DBA去完成——至於怎么降低DBA操作的風險,大概就得靠制度了。
-
參考:
【1】:邏輯刪除實現方案
【2】:邏輯刪除還是物理刪除
【4】:使用binlog日志恢復MySQL數據庫刪除數據的方法
【5】:實現數據邏輯刪除的一種方案
【6】:邏輯刪除實現方案