Silme işlemleri veritabanında nasıl yapılmalıdır?


44

Bir web uygulamasında, bir kullanıcının fikrini değiştirebileceği ve silinen bir kaydı geri kazanabileceği bir "geri alma" özelliği uygulamak istiyorum. Bunun nasıl uygulanacağı üzerine düşünceler? Düşündüğüm bazı seçenekler aslında söz konusu kaydı siliyor ve değişiklikleri ayrı bir denetim masasına kaydediyor ya da kaydı silmiyor ve silinmiş olarak işaretlemek için bir boole "silinmiş" sütun kullanıyor. İkinci çözüm, normal koşullar altında "silinen" kayıtları yok saymak için ek uygulama mantığı gerektirir, ancak uygulama tarafındaki kayıtların kurtarılmasının uygulanmasını çok daha kolay hale getirir.


İkinci durumda, işaretlenen kayıtların makul bir geçen süre sonunda silinmesi veya taşınması gerektiğinden bahsetmeyi unuttum.
Abie

Hangi veritabanını kullanıyorsunuz?
Evan Carroll,

Geçici Tablo, SQL Server 2016 ve üzeri için en iyi çözümdür.
Sameer

Yanıtlar:


37

Evet, kesinlikle ikinci seçeneğe giderdim, ama bir tane daha tarih alanı ekleyeceğim.

Yani siz ekleyin:

delete       boolean
delete_date  timestamp

Geri alma işlemi için zaman ayırmanıza izin verir.

Zaman bir saatten azsa biri geri alınabilir.

Silinen girişi gerçekten silmek için, her girişi silmek için doğru ve bir saatten daha uzun bir süre ayarlanmış ve her 24 saatte bir çalışan bir cron sekmesi olarak koymak için her girişi temizleyen bir saklı yordam oluşturun.

Saat sadece bir örnek.


Alternatif olarak, cleanedbu kayıtla ilişkili verilerin doğru ve kapsamlı bir şekilde silindiğini belirten başka bir bayrağa ( ya da başka bir şeye) sahip olabilirsiniz . cleanedDoğru olmadığı sürece kayıt geri alınabilir , bu durumda kurtarılamaz.
Gaurav,

14
Bu ortak bir yaklaşımdır. Genellikle deleted_athem deleteboole anlamını hem de delete_datezaman damgasını tutan bir alan kullanırım . Eğer deleted_atis NULLidare vaka deleteolduğu FALSEve delete_dateolduğu NULL, deleted_atdava zaman damgası kolu içeren deletebir TRUEve delete_datesize zaman, depolama ve uygulama mantığını tasarruf bir zaman damgası içerir.
Julien

1
Boole ve tarih alanını seviyorum. Silme mantığını nasıl uyguladığınıza bağlı olarak, "silinen" kaydın tarihini ve benzersiz anahtarını içeren ayrı bir tablo bile olabilir. Saklı yordamlar bunu kolaylaştırır. 8 + 'ya karşılık 1 bit'e kadar gereken sıra başına ek boşluğu alır. Kaynak tabloya dokunmadan günlük silme raporları da verebilirsiniz.
AndrewSQL

Not: Silme MySQL'de ayrılmış bir kelimedir.
Jason Rikard

Senin üzerinde süzülmüş endeks unutmayın deletedalanında büyük ölçüde delesyona satırlar için sorguladığınız performansı artırabilir
Ross Baskı

21

Uygulamalarımızda biz değil gerçekten bir kullanıcılar (müşterilerimiz silerek potansiyel hukuki sorunlara yol açabilir düzenlenmiş ortamlarda vardır) zaten talep de silme bir şey.

Eski sürümleri ayrı bir denetim tablosunda tutarız (bu nedenle, bazı sürümler için, bazı bölümler için de bazı tablolar da vardır), ek sürüm tanımlayıcılarına (DB'niz zaman değerlerini yeterince ayrıntılı gösteriyorsa bir zaman damgası, tam sayı sürüm numarası varsa) aynıdır. veya genel bir denetim masasına yabancı bir anahtar olan UUID, vb.) ve denetim masasını otomatik olarak tetikleyerek güncelleyin (bu nedenle, denetim gereksinimlerinden haberdar olan kayıtları güncelleyen tüm kodları yapmamız gerekmez).

Bu yoldan:

  • silme işlemi sadece basit bir silmedir - buna herhangi bir ilave kod eklemenize gerek yoktur (gerçekte silinmemiş olsalar bile hangi satırların silinmesini istediğini kaydetmek isteyebilirsiniz).
  • ekler ve güncellemeler benzer şekilde basittir
  • "normal" satırı eski bir sürüme döndürerek geri alma veya geri alma işlemini uygulayabilirsiniz (denetim tetikleyicisi yeniden tetiklenecek, böylece denetim izi tablosu bu değişikliği yansıtacaktır)
  • Sadece sonuncuyu geri almamakla birlikte herhangi bir eski sürüme inceleme veya geri dönme şansı sunabilirsiniz
  • "silindi olarak işaretlendi mi?" Söz konusu tabloya atıfta bulunan her kod noktasını kontrol eder veya satırları silen / güncelleyen her kod noktasına "denetim kopyası kopyala" mantığını denetler (denetim tablosundaki silinmiş satırlarla ne yapmanız gerektiğine karar vermeniz gerekmesine rağmen) her sürüm için silinen / işaretlenmeyen bu nedenle kayıtlar silinir ve daha sonra silinmemişse, tarihte bir boşluk olmaz.)
  • Denetim kopyalarını ayrı bir tabloda tutmak, bunları kolayca farklı dosya gruplarına bölebileceğiniz anlamına gelir.

Bir tamsayı sürüm numarası yerine (veya bununla birlikte) bir zaman damgası kullanıyorsanız, eski kopyaları gerekirse belirli bir süre sonra silmek için kullanabilirsiniz. Ancak disk alanı bugünlerde nispeten ucuz, bu nedenle eski verileri bırakmak için bir nedenimiz olmadığı sürece (yani, müşteri verilerini X ay / yıl sonra silmeniz gerektiğini söyleyen veri koruma yönetmelikleri) olmaz.


Bu cevap birkaç yıl civarında olmuştur ve bu tür planlamayı etkileyebilecek birkaç önemli şey o zamandan beri değişmiştir. Büyük bir ayrıntıya girmeyeceğim, ancak bugün bunu okuyan insanların yararına açık bir şekilde inanıyorum:

  • SQL Server 2016, sizin için bu işin çoğunu yapan "sistem versiyonlu geçici tablolar" ı tanıttı ve bunun yanında, tarihi sorguların oluşturulmasını ve sürdürülmesini kolaylaştırmak için bazı güzel sözdizimsel şekerler sağlandı ve bunlar arasındaki şema değişikliklerinin bir alt kümesini koordine etti. taban ve tarihçe tabloları. Uyarıları olmadan değiller, ancak bu amaç için güçlü bir araç. Benzer özellikler diğer DB sistemlerinde de mevcuttur.

  • Özellikle GDPR'nin uygulamaya konması olan veri koruma mevzuatındaki değişiklikler, verilerin ne zaman silinmesinin zor olduğu konusunu önemli ölçüde değiştirebilir. İnsan hakları haklarına saygı duyulması gerekliliğine karşı (genel olarak ve ilgili mevzuatta özel olarak belirtildiği gibi) denetleme amacıyla yararlı olabilecek (ya da yasal olarak gerekli) veriyi silmemenin dengesini tartmalısınız. Tasarımların Bu, sistem versiyonundaki geçici tablolarla ilgili bir sorun olabilir, çünkü değişiklik yaparken tarih takibini kapatmak için şema kısa vadeli değişiklikler olmadan kişisel verileri temizlemek için geçmişi değiştiremezsiniz.


Sütunları silme ve yeniden adlandırma ile nasıl başa çıkıyorsunuz? Her şeyi boşuna mı ayarladın?
Stijn

1
@Stijn: Yapıların sık sık değişmediği için pek fazla ortaya çıkmaz. Sütunlar genellikle üretimde var olduklarında asla kaldırılmazlar - kullanılmayı bırakırlarsa, NULL üzerinde durduracak herhangi bir kısıtlama bırakmazlar (veya "sihirli bir değer" kullanarak kısıtlamalarla baş etmek için varsayılanları ekleyin, ancak bu daha kirli hissettirir) ve diğer kodlarda bunlara atıfta bulunmayı bırakın. Adlar için: yeni ekleyin, eskisi kullanmayı bırakın ve gerekirse verileri eskiden yeniye kopyalayın. Sütunları yeniden adlandırırsanız, aynı anda hem temel hem de denetim tablolarında aynı değişikliğin yapıldığından emin olun.
David Spillett

9

Boolean silinmiş bir sütunla, tablonuz büyümeye başlar ve gerçekten büyürse sorun yaşamaya başlarsınız. Silinen sütunları haftada bir (teknik özelliklere bağlı olarak az ya da çok) farklı bir tabloya taşımanızı öneririm. Böylelikle hoş bir küçük aktif masaya ve zaman içinde toplanmış tüm kayıtları içeren büyük bir masaya sahip olursunuz.


7

Ayrı masaya giderdim. Ruby on Rails, acts_as_versionedeklentiyi _versiongüncellemeden önce temelde bir satırı diğer bir tabloya kaydeder . Bu kesin davranışa ihtiyacınız olmasa da, davanız için de çalışmalıdır (silmeden önce kopyalayın).

@ Spredzy gibi ben de delete_dateX saat / gün / neyse sonra geri yüklenmemiş kayıtları programlı olarak temizleyebilmek için bir sütun eklemenizi tavsiye ederim .


4

Bu konuda dahili olarak kullandığımız çözüm, nesnenin belirli durumları için bazı sabit kodlanmış değerlere sahip bir durum sütununa sahip olmaktır: Silinmiş, Aktif, Aktif Değil, Açık, Kapalı, Engellenmiş - Uygulamada kullanılan her durum için her durum. Db bakış açısından nesneleri kaldırmıyoruz, sadece durumu değiştiriyoruz ve nesne tablosundaki her değişiklik için geçmişi tutuyoruz.


3

“İkinci çözüm,“ silinen ”kayıtları yok saymak için ek uygulama mantığı gerektirecektir, derken, basit çözüm onları filtreleyen bir görünüme sahip olmaktır.


Bu sadece bir bakış açısı değil. Sette gerçekleştirilen tüm işlemlerin "silinen" kayıtları dışlaması gerekir.
Abie

2

Spredzy'nin önerdiği gibi, tüm uygulamalarımızda silmek için zaman damgası alanı kullanıyoruz. Boolean gereksizdir, çünkü ayarlanan zaman damgası kaydın silindiğini gösterir. Bu yolla, PDO'muz AND (deleted IS NULL OR deleted = 0), model açıkça silinmiş kayıtların dahil edilmesini istemediği sürece, her zaman select ifadelerini ekler .

Şu anda çöp veya yazı içeren masalar dışında çöp toplamıyoruz; eğer kayıtlar normalize edilmişse, alan önemsizdir ve deletedalanın indekslenmesi seçilen hız üzerinde sınırlı etki yaratır.


0

Alternatif olarak kullanıcılara kullanıcılara (ve geliştiricilere) yer verebilir ve 'Emin misiniz?', 'Kesinlikle emin misiniz?' ve 'Kesinlikle, iyi ve gerçekten emin misiniz?' Kayıt silinmeden önceki sorular. Hafif fasetious ama dikkate değer.


0

Tablo satırlarını 'DeletedDate' gibi sütunlarla görmeye alışkınım ve onlardan hoşlanmıyorum. “Silinen” kavramı, girişin ilk başta yapılmaması gerektiği yönündedir. Pratik olarak, veritabanından kaldırılamazlar, ancak sıcak verilerimle birlikte olmasını istemiyorum. Mantıksal olarak silinmiş satırlar, birileri özellikle silinmiş verileri görmek istemediği sürece, tanım olarak soğuk verilerdir.

Ayrıca, yazılan her sorgu, onları özel olarak dışlamak zorundadır ve dizinlerin de göz önünde bulundurulması gerekir.

Görmek istediğim, veritabanı mimarisi düzeyinde ve uygulama düzeyinde bir değişiklik: 'deleted' adlı bir şema oluşturun. Her kullanıcı tanımlı tablo, 'silinen' şemada, meta verileri içeren ekstra bir alanla - onu ne zaman ve ne zaman sildiğini belirten eşdeğerdedir. Yabancı anahtarların oluşturulması gerekiyor.

Sonra, siler ekleme-silmeye dönüşür. Öncelikle silinecek satır 'silinmiş' şema emsaline eklenir. Ana tabloda söz konusu satır daha sonra silinebilir. Bununla birlikte, ekstra mantığın hat boyunca bir yere eklenmesi gerekir. Yabancı anahtar ihlalleri ele alınabilir.

Yabancı anahtarların doğru şekilde kullanılması gerekir. Mantıksal olarak silinmiş ancak birincil / benzersiz olan diğer tablolarda kendisine ait sütunlar bulunan bir satırın olması kötü bir uygulamadır. Bu zaten olmamalıydı. Düzenli bir iş, dul satırlarını kaldırabilir (birincil anahtarının yabancı anahtar olmasına rağmen diğer tablolarda referansı olmayan satırlar). Bu, iş mantığıdır.

Genel yarar tablodaki meta verilerin azaltılması ve getirdiği performans iyileştirmesidir. 'DeletedDate' sütunu bu satırın aslında burada olmaması gerektiğini, ancak kolaylık uğruna orada bıraktığımızı ve SQL sorgusunun işlemesine izin verdiğini söylüyor. Silinen satırın bir kopyası 'silinmiş' bir şemada tutulursa, sıcak verilere sahip ana tablo daha yüksek bir sıcak veri yüzdesine (zamanında arşivlendiği varsayılarak) ve daha az gereksiz meta veri sütununa sahiptir. Dizinlerin ve sorguların bu alanı dikkate almasına artık gerek yok. Satır boyutu ne kadar kısa olursa, bir sayfaya o kadar çok satır eklenebilir, SQL Server daha hızlı çalışabilir.

En büyük dezavantaj, operasyonun büyüklüğüdür. Artık bir mantıksal ve hata işleme yerine tek bir işlem yerine iki işlem var. Aksi takdirde tek bir sütunu güncellemekten daha fazla kilitlenmeye yol açabilir. İşlem masanın üzerindeki kilitleri daha uzun tutar ve ilgili iki tablo vardır. Üretim verilerini silmek, en azından benim deneyimime göre, nadiren yapılır. Yine de, ana tablolardan birinde, yaklaşık 100 milyon girişin% 7,5'inde 'DeletedDate' sütununda bir giriş var.

Sorunun cevabı olarak, uygulamanın 'geri alınmamışların' farkında olması gerekir. Aynı işlemi tersi sırayla yapmanız gerekecektir: 'silinmiş' şemadaki satırı ana tabloya ekleyin ve sonra 'silinmiş şemadan satırı silin. Yine hatalardan, yabancı anahtarlarla ve benzeri sorunlardan kaçınmak için bazı ekstra mantık ve hata yönetimi gereklidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.