Aby poprawnie odpowiedzieć na to pytanie, musisz najpierw zdecydować: co oznacza „usuń” w kontekście tego systemu / aplikacji?
Aby odpowiedzieć na to pytanie, trzeba odpowiedzieć na kolejny pytanie: Dlaczego są zapisy zostać usunięty?
Istnieje wiele dobrych powodów, dla których użytkownik może potrzebować do danych usunąć. Zwykle uważam, że istnieje dokładnie jeden powód (na stole), dlaczego kasowania może być konieczne. Oto niektóre przykłady:
- Aby odzyskać miejsce na dysku;
- Hard-usunięcie wymagane zgodnie z polityką prywatności / retencji;
- Uszkodzony / beznadziejnie błędne dane, łatwiej usuwać i regenerują niż do naprawy.
- Większość wierszy są usuwane, np tabeli dziennika ograniczone do rejestrów X / dzień.
Istnieje również kilka bardzo słabych powodów twardego usuwania (więcej o przyczynach później):
- Aby poprawić błąd Mniejszej. Zwykle podkreśla lenistwo programistów i UI wrogie.
- Do „void” transakcji (np faktury, które powinny nigdy nie zostały rozliczone).
- Bo może .
Dlaczego, można zapytać, czy naprawdę jest to taka wielka sprawa? Co złego jest w dobrej ole” DELETE
?
- W każdym systemie nawet zdalnie przywiązany do pieniędzy, ciężko narusza usunięcie wszelkiego rodzaju oczekiwań księgowe, nawet jeśli przeniósł się do tabeli archiwum / nagrobek. Prawidłowym sposobem radzenia sobie z tym jest zdarzenie wsteczne .
- Stoły Archive mają tendencję do odchylania się od schematu na żywo. Jeśli zapomnisz nawet o jednej nowo dodanej kolumnie lub kaskadzie, właśnie utraciłeś te dane na stałe.
- Ciężko usunięcie może być bardzo kosztowna operacja, zwłaszcza z kaskadami . Wiele osób nie zdaje sobie sprawy, że kaskadowe więcej niż jeden poziom (lub w niektórych przypadkach każdy kaskadowy, zależnie od DBMS) spowoduje operacji na poziomie rekordu zamiast zestawu operacji.
- Powtarza się często trudne usunięcie przyspiesza proces rozdrobnienia indeksu.
Tak miękkie kasowania jest lepiej, prawda? Nie, nie bardzo:
- Konfigurowanie kaskady staje się niezwykle trudne. Prawie zawsze skończyć z tym, co wydaje się klientowi jako osieroconych wierszy.
- Można dostać tylko do śledzenia jednej usunięcie. Co zrobić, jeśli rząd zostanie usunięty i przywrócił wiele razy?
- Wydajność odczytu spada, chociaż można to nieco złagodzić za pomocą partycjonowania, widoków i / lub filtrowanych indeksów.
- Jak zasugerował wcześniej, to może faktycznie być nielegalne w niektórych scenariuszach / jurysdykcjach.
Prawda jest taka, że oba te podejścia są błędne. Usuwanie jest źle. Jeśli rzeczywiście tym pytaniem to znaczy, jesteś modelowania aktualny stan zamiast transakcji. Jest to zła, zła praktyka w obszarze bazy danych.
Udi Dahan napisał o tym w Don't Don't - Just Don't . Zawsze istnieje jakieś zadanie, transakcja, aktywność lub (moje preferowane pojęcie) zdarzenie, które faktycznie reprezentuje „usuń”. Jest OK, jeśli chcesz denormalize następnie w „stan obecny” stół do wydajności, ale zrobić to po już przybita modelu transakcyjnym, a nie przed.
W tym przypadku masz „użytkowników”. Użytkownicy są głównie klienci. Klienci mają stosunki handlowe z Państwem. Ten związek nie rozpłynie się w powietrzu, ponieważ anulowali swoje konto. Co się naprawdę dzieje, jest:
- Klient tworzy konto
- Klient anuluje konto
- Klient odnawia konto
- Klient anuluje konto
- ...
W każdym razie, jest to ten sam klient , i ewentualnie samego konta (czyli każdego przedłużenia konta to nowa umowa serwisowa). Więc czemu usuwanie wierszy? Jest to bardzo łatwe do modelu:
+-----------+ +-------------+ +-----------------+
| Account | --->* | Agreement | --->* | AgreementStatus |
+-----------+ +-------------+ +----------------+
| Id | | Id | | AgreementId |
| Name | | AccountId | | EffectiveDate |
| Email | | ... | | StatusCode |
+-----------+ +-------------+ +-----------------+
Otóż to. To wszystko. Nigdy nie trzeba niczego usuwać. Powyższe jest dość powszechne projekt, który może pomieścić dobrą elastyczność, ale można uprościć to trochę; może zdecydować, że nie trzeba poziom „Umowa” i po prostu „Konto” idź do stołu „AccountStatus”.
Jeśli często potrzeba w danej aplikacji jest uzyskać listę aktywnych umów / rachunki to jest to (nieznacznie) zapytanie trudne, ale to właśnie poglądy są dla:
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
)
I jesteś skończony. Teraz masz coś ze wszystkimi zaletami miękkiego usuwania, ale nie ma żadnych wad:
- Osierocone rekordy nie stanowią problemu, ponieważ wszystkie rekordy są widoczne przez cały czas; w razie potrzeby po prostu wybierasz z innego widoku.
- „Usuwanie” jest zwykle niezwykle tanią operacją - wystarczy wstawić jeden wiersz do tabeli zdarzeń.
- Nigdy nie jest jakaś szansa utraty historię, nigdy , bez względu na to jak bardzo zepsuć.
- Nadal możesz usunąć konto, jeśli zajdzie taka potrzeba (np. Ze względu na prywatność), i zachowaj wygodę, wiedząc, że usunięcie nastąpi czysto i nie będzie kolidować z żadną inną częścią aplikacji / bazy danych.
Jedynym problemem w lewo do rozwiązania jest kwestia wydajności. W wielu przypadkach to rzeczywiście okazuje się, że to nie problem, bo z indeksu klastrowego AgreementStatus (AgreementId, EffectiveDate)
- jest bardzo niewiele I / O szukając tam dzieje. Ale jeśli to jest zawsze problem, istnieją sposoby, aby rozwiązać ten, za pomocą wyzwalaczy, indeksowane / zmaterializowane perspektywy, zdarzeń na poziomie aplikacji, etc.
Nie martw się o wydajności zbyt wcześnie, chociaż - to ważne, aby uzyskać prawo do projektowania i „prawo” oznacza w tym przypadku korzystania z bazy danych tak, jak baza danych ma być używany, jako transakcyjnej systemu.