相信不少人都聽過刪庫跑路
這個詞,用搜索引擎檢索刪庫跑路
,能夠看到不少程序員刪庫跑路的討論和新聞。html
可是,嚴格來說,大部分程序員想刪庫跑路
也作不到。爲何呢?由於沒有數據庫的刪除權限。——真正能刪庫跑路
的是運維,再準確點DBA。mysql
那麼平時業務中的刪除是怎麼作的呢?答案是邏輯刪除
。git
邏輯刪除:又名軟刪除,與物理刪除、硬刪除相對應,含義是並無實際的刪除數據,只是將數據標記已刪除
(例如增長is_deleted字段)。程序員
物理刪除
很好理解,就是真的把數據給刪了。github
以MySQL爲例,假如數據刪了,應該怎麼恢復呢?主要方式有兩種。sql
利用 binlog 日誌數據庫
binlog是記錄全部數據庫表結構變動(例如CREATE、ALTER TABLE…)以及表數據修改(INSERT、UPDATE、DELETE…)的二進制日誌。安全
使用binlog恢復數據,本質上就是經過binlog找到全部DML操做,去掉錯誤的SQL語句,而後執行其它的SQL語句,就能夠將數據恢復。框架
binlog恢復數據示意圖以下:運維
能夠看到,恢復時候不只須要停掉數據庫,假如數據量大的話,去篩選恢復數據sql就😂
數據庫延時同步節點
因此,綜上,能夠認識到,數據刪除以後的恢復是要付出很大代價的,並且還存在不可恢復的風險。因此出於安全考慮,生產環境數據庫應當儘量禁止物理刪除
。
這個不用說,數據沒有實際刪除,天然會產生大量的對業務無用的冗餘數據。
寫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】:邏輯刪除實現方案