天天看點

資料庫,邏輯删還是實體删?為什麼要用邏輯删除?邏輯删除會帶來什麼問題?如何設計邏輯删除?應該用邏輯删除嗎?

相信很多人都聽過

删庫跑路

這個詞,用搜尋引擎檢索

删庫跑路

,可以看到很多程式員删庫跑路的讨論和新聞。
資料庫,邏輯删還是實體删?為什麼要用邏輯删除?邏輯删除會帶來什麼問題?如何設計邏輯删除?應該用邏輯删除嗎?
但是,嚴格來講,大部分程式員想

删庫跑路

也做不到。為什麼呢?因為沒有資料庫的删除權限。——真正能

删庫跑路

的是運維,再準确點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 t2.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操作的風險,大概就得靠制度了。