Chciałbym zaimplementować funkcję „cofania” w aplikacji internetowej, aby użytkownik mógł zmienić zdanie i odzyskać usunięty zapis. Myśli, jak to wdrożyć? Niektóre opcje, które rozważałem, to w rzeczywistości usunięcie danego rekordu i zapisanie zmian w osobnej tabeli audytu lub nieusunięcie rekordu i użycie logicznej kolumny „usunięto”, aby oznaczyć go jako usunięty. To ostatnie rozwiązanie wymagałoby dodatkowej logiki aplikacji, aby zignorować „usunięte” rekordy w normalnych okolicznościach, ale znacznie ułatwiłoby wdrożenie odzyskiwania rekordów po stronie aplikacji.
database-design
delete
audit
Abie
źródło
źródło
Odpowiedzi:
Tak, zdecydowanie wybrałbym drugą opcję, ale dodałbym jeszcze jedno pole pole daty.
Więc dodajesz:
Pozwoli ci to dać czas na usunięcie operacji.
Jeśli czas jest krótszy niż godzina, można cofnąć usunięcie.
Aby naprawdę usunąć usunięty wpis, po prostu stwórz procedurę składowaną, która wyczyści każdy wpis z ustawionym parametrem usuwania i czasem dłuższym niż jedna godzina i umieści go jako zakładkę cron, która będzie uruchamiana co 24 godziny
Godzina jest tylko przykładem.
źródło
cleaned
lub coś - co wskazuje, że dane powiązane z tym rekordem zostały poprawnie, kompleksowo usunięte. Rekord może zostać cofnięty, chyba żecleaned
jest prawdziwy, w takim przypadku nie można go odzyskać.deleted_at
zawierającego zarówno semantyczną wartośćdelete
logiczną, jak idelete_date
znacznik czasu. Jeślideleted_at
jestNULL
obsługiwany, sprawadelete
jestFALSE
idelete_date
jestNULL
,deleted_at
zawierająca uchwyt znacznika czasu, sprawadelete
jestTRUE
idelete_date
zawiera znacznik czasu, co oszczędza czas, pamięć i logikę aplikacji.deleted
polu może znacznie poprawić wydajność, gdy pytasz o niededelowane wierszeW naszych aplikacjach tak naprawdę nie usuwamy niczego na żądanie użytkowników (nasi klienci znajdują się w regulowanych środowiskach, w których usuwanie czegokolwiek może potencjalnie prowadzić do problemów prawnych).
Starsze wersje przechowujemy w osobnej tabeli audytu (więc dla tabeli tabela_tablic, gdzie jest również tabela o nazwie tabela_tablicy_tablicy), która jest identyczna oprócz posiadania dodatkowego identyfikatora wersji (znacznik czasu, jeśli twoja baza danych obsługuje wystarczająco szczegółowe wartości czasu, numer wersji całkowitej) lub UUID, który jest kluczem obcym do ogólnej tabeli kontroli itp., i automatycznie aktualizuj tabelę kontroli za pomocą wyzwalacza (więc nie musimy informować całego kodu aktualizującego rekordy o wymaganiu kontroli).
Tą drogą:
Jeśli używasz znacznika czasu zamiast (lub również jako) liczb całkowitych wersji, możesz użyć tego, aby usunąć starsze kopie po określonym czasie, jeśli to konieczne. Ale przestrzeń dyskowa jest obecnie stosunkowo tania, więc jeśli nie mamy powodu, aby upuścić stare dane (tj. Przepisy dotyczące ochrony danych, które mówią, że powinieneś usunąć dane klienta po X miesiącach / latach), nie zrobilibyśmy tego.
Ta odpowiedź trwa już kilka lat i od tego czasu zmieniło się kilka kluczowych rzeczy, które mogą wpłynąć na tego rodzaju planowanie. Nie zajmę się szczegółowymi szczegółami, ale krótko dla korzyści osób czytających to dzisiaj:
SQL Server 2016 wprowadził „tabele czasowe z wersją systemową”, które wykonują dla ciebie wiele pracy, a ponadto, ponieważ zapewniono trochę miłego cukru syntaktycznego, aby ułatwić tworzenie i obsługę zapytań historycznych oraz koordynować podzbiór zmian schematu między tabele podstawowe i historyczne. Nie są obojętni, ale są potężnym narzędziem do tego celu. Podobne funkcje są również dostępne w innych systemach DB.
Zmiany w przepisach dotyczących ochrony danych, w szczególności wprowadzenie RODO, mogą znacząco zmienić kwestię, kiedy dane powinny zostać trwale usunięte. Musisz rozważyć równowagę między nieusługiwaniem się danymi, które mogą być przydatne (a nawet wymagane przez prawo) do celów audytu w późniejszym terminie, a koniecznością poszanowania praw ludzi (zarówno ogólnie, jak i szczegółowo określonych w odpowiednich przepisach) przy rozważaniu twoje projekty. Może to być problem z tabelami czasowymi w wersji systemowej, ponieważ nie można modyfikować historii w celu wyczyszczenia danych osobowych bez krótkoterminowych zmian schematu w celu wyłączenia śledzenia historii podczas wprowadzania zmian.
źródło
Z kolumną usuniętą boolean zaczniesz mieć problemy, jeśli twoja tabela zacznie rosnąć i stanie się naprawdę duża. Sugeruję przeniesienie usuniętych kolumn raz w tygodniu (mniej więcej w zależności od specyfikacji) do innej tabeli. W ten sposób masz ładny mały aktywny stół i duży zawierający wszystkie rekordy zebrane w czasie.
źródło
Poszedłbym z oddzielnym stołem. Ruby on Rails ma
acts_as_versioned
wtyczkę, która zasadniczo zapisuje wiersz do innej tabeli z postfiksem_version
przed jego aktualizacją. Chociaż nie potrzebujesz tego dokładnego zachowania, powinno również działać w twoim przypadku (skopiuj przed usunięciem).Podobnie jak @Spredzy polecam również dodanie
delete_date
kolumny, aby móc programowo wyczyścić rekordy, które nie zostały przywrócone po X godzinach / dniach / czymkolwiek.źródło
Rozwiązaniem, którego używamy wewnętrznie w tej sprawie, jest kolumna stanu z pewnymi zakodowanymi wartościami dla niektórych określonych stanów obiektu: Usunięte, Aktywne, Nieaktywne, Otwarte, Zamknięte, Zablokowane - każdy status ma pewne znaczenie użyte w aplikacji. Z punktu widzenia db nie usuwamy obiektów, po prostu zmieniamy status i przechowujemy historię dla każdej zmiany w tabeli obiektów.
źródło
Kiedy powiesz, że „to drugie rozwiązanie wymagałoby dodatkowej logiki aplikacji, aby zignorować„ usunięte ”rekordy”, prostym rozwiązaniem jest widok, który je odfiltrowuje.
źródło
Podobnie jak sugerował Spredzy, używamy pola znacznika czasu do usuwania we wszystkich naszych aplikacjach. Wartość logiczna jest zbędna, ponieważ ustawienie znacznika czasu wskazuje, że rekord został usunięty. W ten sposób nasz ChNP zawsze dodaje
AND (deleted IS NULL OR deleted = 0)
do instrukcji select, chyba że model wyraźnie zażąda włączenia usuniętych rekordów.Obecnie nie zbieramy śmieci w żadnym z wyjątkiem tabel zawierających obiekty BLOB lub teksty; przestrzeń jest trywialna, jeśli rekordy są dobrze znormalizowane, a indeksowanie
deleted
pola ma ograniczony wpływ na wybraną prędkość.źródło
Alternatywnie możesz nałożyć ciężar na użytkowników (i programistów) i przejść do sekwencji „Jesteś pewien?”, „Czy na pewno jesteś pewien?” i „Czy jesteś absolutnie, dobrze i naprawdę pewny?” pytania przed usunięciem rekordu. Mało żartobliwe, ale warte rozważenia.
źródło
Przyzwyczaiłem się do wyświetlania wierszy tabeli z kolumnami takimi jak „Usunięte” i nie lubię ich. Samo pojęcie „skreślony” polega na tym, że wpis nie powinien był zostać dokonany w pierwszej kolejności. Praktycznie nie można ich usunąć z bazy danych, ale nie chcę ich z moimi gorącymi danymi. Logicznie usunięte wiersze są z definicji zimnymi danymi, chyba że ktoś konkretnie chce zobaczyć usunięte dane.
Ponadto każde napisane zapytanie musi je konkretnie wykluczać, a indeksy również je uwzględniają.
Chciałbym zobaczyć zmianę na poziomie architektury bazy danych i na poziomie aplikacji: utwórz schemat o nazwie „usunięty”. Każda tabela zdefiniowana przez użytkownika ma identyczny odpowiednik w schemacie „usuniętym” z dodatkowym polem przechowującym metadane - użytkownika, który ją usunął i kiedy. Konieczne jest utworzenie kluczy obcych.
Następnie usuwa staje się usuwanie-wstawianie. Najpierw wiersz do usunięcia jest wstawiany do jego „usuniętego” odpowiednika schematu. Wiersz w głównej tabeli można następnie usunąć. Należy jednak dodać dodatkową logikę gdzieś wzdłuż linii. Naruszenie klucza obcego można rozwiązać.
Klucze obce muszą być odpowiednio obsługiwane. Złą praktyką jest logiczne usuwanie wiersza, ale którego podstawowy / niepowtarzalny ma kolumny w innych tabelach, które go dotyczą. To i tak nie powinno się zdarzyć. Zwykłe zadanie może usuwać wiersze wdów (wiersze, których klucze podstawowe nie mają odniesień w innych tabelach pomimo obecności klucza obcego. Jest to jednak logika biznesowa.
Ogólną korzyścią jest zmniejszenie metadanych w tabeli i poprawa wydajności. Kolumna „deleteDate” mówi, że ten wiersz nie powinien być tutaj, ale dla wygody zostawiamy go tam i pozwalamy zapytaniu SQL go obsłużyć. Jeśli kopia usuniętego wiersza jest przechowywana w schemacie „usuniętym”, wówczas główna tabela z gorącymi danymi ma wyższy procent gorących danych (zakładając, że jest archiwizowany w odpowiednim czasie) i mniej niepotrzebnych kolumn metadanych. Indeksy i zapytania nie muszą już uwzględniać tego pola. Im mniejszy rozmiar wiersza, tym więcej wierszy można dopasować do strony, tym szybciej działa SQL Server.
Główną wadą jest rozmiar operacji. Istnieją teraz dwie operacje zamiast jednej, a także dodatkowa logika i obsługa błędów. Może to prowadzić do większego blokowania niż aktualizacja pojedynczej kolumny, w przeciwnym razie zajęłoby to. Transakcja utrzymuje blokady na stole dłużej i są zaangażowane dwie tabele. Usuwanie danych produkcyjnych, przynajmniej z mojego doświadczenia, jest rzadkością. Mimo to w jednej z głównych tabel 7,5% z prawie 100 milionów wpisów ma wpis w kolumnie „Usunięte”.
W odpowiedzi na pytanie aplikacja musiałaby mieć świadomość „cofnięcia usunięcia”. Musiałby po prostu zrobić to samo w odwrotnej kolejności: wstawić wiersz ze schematu „usunięty” do głównej tabeli, a następnie usunąć wiersz ze „usuniętego schematu”. Znowu potrzebna jest dodatkowa logika i obsługa błędów, aby uniknąć błędów, problemów z kluczami obcymi i tym podobnych.
źródło