Bu soruyu doğru bir şekilde cevaplamak için önce aşağıdakilere karar vermelisiniz: "Sil" bu sistem / uygulama bağlamında ne anlama geliyor?
Cevaplamak için bu soruyu, henüz başka soruyu cevaplamak gerekir: Neden kayıtları silinir ediliyor?
Bir kullanıcının verileri silmesinin birkaç nedeni olabilir. Genellikle bir silme işleminin gerekli olabileceği tam olarak bir neden (tablo başına) olduğunu bulurum . Bazı örnekler:
- Disk alanını geri kazanmak için;
- Saklama / gizlilik politikasına göre kesin olarak silinmesi gerekir;
- Bozuk / umutsuzca yanlış veriler, silinmekten ve yenilenmekten daha kolay.
- Çoğunluk satır, örneğin bir günlük masa X kayıtları ile sınırlı / gün silinir.
Ayrıca, silmenin çok kötü nedenleri de var (daha sonra bunun nedenleri hakkında daha fazla bilgi):
- Küçük bir hatayı düzeltmek için. Bu genellikle geliştirici tembelliğinin ve düşmanca bir kullanıcı arayüzünün altını çizer.
- Bir işlemi "geçersiz kılmak" (örneğin, asla faturalandırılmaması gereken fatura).
- Çünkü yapabilirsin .
Neden soruyorsun, bu gerçekten çok mu önemli? İyi ole'de sorun nedir DELETE
?
- Uzaktan paraya bağlı herhangi bir sistemde, silinme, bir arşiv / mezar taşı tablosuna taşınsa bile, her türlü muhasebe beklentisini ihlal eder. Bunu ele almanın doğru yolu geriye dönük bir olaydır .
- Arşiv tabloları canlı şemadan ayrılma eğilimindedir. Yeni eklenen bir sütun veya basamaklamayı bile unutursanız, bu verileri kalıcı olarak kaybettiniz.
- Sert silme, özellikle kaskadlarda çok pahalı bir işlem olabilir . Birçok kişi, birden fazla seviyenin basamaklandırılmasının (veya bazı durumlarda DBMS'ye bağlı olarak herhangi bir basamaklamanın) ayarlanan işlemler yerine kayıt düzeyinde işlemlerle sonuçlanacağının farkında değildir .
- Tekrarlanan, sık sık sert silme indeks parçalanması sürecini hızlandırır.
Yumuşak silme daha iyidir, değil mi? Hayır gerçek değil:
- Kaskadlar kurmak son derece zorlaşır. Neredeyse her zaman müşteriye yetim satırlar olarak görünenlerle sonuçlanırsınız.
- Sadece bir silme işlemini takip edebilirsiniz . Satır birden çok kez silinir ve silinirse ne olur?
- Bu, bölümleme, görünümler ve / veya filtrelenmiş dizinlerle bir şekilde azaltılabilmesine rağmen, okuma performansı düşmektedir.
- Daha önce de belirtildiği gibi, bazı senaryolarda / yargı bölgelerinde aslında yasa dışı olabilir.
Gerçek şu ki , bu yaklaşımların her ikisi de yanlıştır. Silme yanlış. Bu soruyu gerçekten soruyorsanız , işlemler yerine mevcut durumu modellediğiniz anlamına gelir . Bu, veritabanı arazisinde kötü, kötü bir uygulamadır.
Udi Dahan bunu Silme - Sadece Yapma bölümünde yazdı . Her zaman , aslında "sil" i temsil eden bir tür görev, işlem, etkinlik veya (tercih ettiğim terim) olayı vardır. Daha sonra performans için bir "mevcut durum" tablosunda denormalize etmek istiyorsanız sorun değil, ancak işlem modelini daha önce değil, çiviledikten sonra yapın.
Bu durumda "kullanıcılarınız" olur. Kullanıcılar aslında müşteridir. Müşterilerin sizinle bir iş ilişkisi var. Bu ilişki sadece ince havaya kaybolmaz, çünkü hesaplarını iptal ederler. Gerçekten olan şey:
- Müşteri hesap oluşturur
- Müşteri hesabı iptal eder
- Müşteri hesabı yeniler
- Müşteri hesabı iptal eder
- ...
Her durumda, aynı müşteri ve muhtemelen aynı hesaptır (yani her hesap yenilemesi yeni bir hizmet sözleşmesidir). Öyleyse neden satırları siliyorsunuz? Bunu modellemek çok kolaydır:
+-----------+ +-------------+ +-----------------+
| Account | --->* | Agreement | --->* | AgreementStatus |
+-----------+ +-------------+ +----------------+
| Id | | Id | | AgreementId |
| Name | | AccountId | | EffectiveDate |
| Email | | ... | | StatusCode |
+-----------+ +-------------+ +-----------------+
Bu kadar. Hepsi bu kadar. Hiçbir şeyi silmenize gerek yoktur. Yukarıdakiler, iyi bir esneklik derecesini barındıran oldukça yaygın bir tasarımdır, ancak biraz basitleştirebilirsiniz; "Sözleşme" düzeyine ihtiyacınız olmadığına ve yalnızca "Hesap" ın bir "Hesap Durumu" tablosuna gitmesine karar verebilirsiniz.
Uygulamanızda sıkça ihtiyaç duyulan bir şey, aktif sözleşmelerin / hesapların bir listesini almaksa, (biraz) zor bir sorgudur, ancak görünümler bunun içindir:
CREATE VIEW ActiveAgreements AS
SELECT agg.Id, agg.AccountId, acc.Name, acc.Email, s.EffectiveDate, ...
FROM AgreementStatus s
INNER JOIN Agreement agg
ON agg.Id = s.AgreementId
INNER JOIN Account acc
ON acc.Id = agg.AccountId
WHERE s.StatusCode = 'ACTIVE'
AND NOT EXISTS
(
SELECT 1
FROM AgreementStatus so
WHERE so.AgreementId = s.AgreementId
AND so.EffectiveDate > s.EffectiveDate
)
Ve işiniz bitti. Artık yumuşak silme işlemlerinin tüm avantajlarına sahip bir şey var, ancak hiçbir dezavantajı yok:
- Artık kayıtlar sorun teşkil etmez, çünkü tüm kayıtlar her zaman görülebilir; sadece gerektiğinde farklı bir görünümden seçim yaparsınız.
- "Silme" genellikle inanılmaz derecede ucuz bir işlemdir - bir olay tablosuna bir satır eklemek yeterlidir.
- Herhangi tarihlerini kaybetme ihtimali var asla hiç , hayır berbat ne kadar kötü bir önemi.
- Hala bir hesap sert silebilirsiniz eğer sen (gizlilik nedeniyle örneğin) gerekir ve silme temiz ve gerçekleşmesi app / veritabanının diğer kısımları müdahale edeceği bilgisiyle rahat.
Üstesinden gelinmesi gereken tek şey performans sorunudur. Birçok durumda, aslında kümelenmiş dizin nedeniyle bir sorun olmadığı ortaya çıkıyor AgreementStatus (AgreementId, EffectiveDate)
- orada devam eden çok az G / Ç var. Ancak, herhangi bir sorun varsa, tetikleyicileri, dizine eklenmiş / materyalize edilmiş görünümleri, uygulama düzeyinde etkinlikleri vb. Kullanarak çözmenin yolları vardır.
Ancak performans hakkında çok erken endişelenmeyin - tasarımı doğru yapmak daha önemlidir ve bu durumda "doğru", veritabanını işlemsel bir sistem olarak kullanılması gerektiği şekilde kullanmaktır .