Jak ogólnie zapisywane jest zapisywanie każdej zmiany wiersza w bazie danych?

10

W projekcie, nad którym pracuję, każda zmiana wierszy w niektórych tabelach bazy danych musi być śledzona w celu dalszego audytu lub wycofania. Musi być łatwo ustalić, kto zmodyfikował wiersz, z którego adresu IP i kiedy, i móc przywrócić poprzednią wersję.

Podobna rzecz jest używana na przykład przez Stack Exchange. Kiedy zmieniam pytanie innej osoby, można stwierdzić, że je zmieniłem i wycofać zmiany.

Jaka jest ogólna technika przechowywania każdej zmiany w obiekcie w bazie danych , biorąc pod uwagę, że mój obecny schemat ma w większości te same właściwości (poniżej), co przeciętna aplikacja biznesowa?

  • Obiekty mają stosunkowo niewielki rozmiar: mogą być nvarchar(1000)na przykład niektóre , ale nie ogromne plamy danych binarnych, które są przechowywane bezpośrednio na dysku i dostępne bezpośrednio, a nie poprzez Microsoft SQL filestream,
  • Obciążenie bazy danych jest dość niskie, a cała baza danych jest obsługiwana przez jedną maszynę wirtualną na serwerze,
  • Dostęp do poprzednich wersji nie musi być tak szybki jak dostęp do najnowszej wersji, ale wciąż musi być aktualny¹ i niezbyt wolny².

<tl-dr>

Myślałem o następujących przypadkach, ale nie mam prawdziwego doświadczenia z tego rodzaju scenariuszami, więc chciałbym usłyszeć opinie innych:

  1. Przechowuj wszystko w tej samej tabeli, rozróżniając wiersze według identyfikatora i wersji. IMO, to jest naprawdę głupie i zaszkodzi prędzej czy później na poziomie wydajności. Przy takim podejściu niemożliwe jest również ustawienie innego poziomu bezpieczeństwa dla najnowszych elementów i śledzenia wersji. Wreszcie każde zapytanie byłoby trudniejsze do napisania. W rzeczywistości, aby uzyskać dostęp do aktualnych danych, byłbym zmuszony pogrupować wszystko według identyfikatora i pobrać w każdej grupie ostatnią wersję.

  2. Przechowuj najnowszą wersję w jednej tabeli i przy każdej zmianie kopiuj przestarzałą wersję do innej tabeli w innym schemacie. Wada polega na tym, że za każdym razem przechowujemy każdą wartość, nawet jeśli się nie zmieniła. Ustawienie niezmienionych wartości na nullnie jest rozwiązaniem, ponieważ muszę także śledzić, kiedy wartość jest zmieniana na nulllub z null.

  3. Przechowuj najnowszą wersję w jednej tabeli, a listę zmienionych właściwości wraz z ich poprzednimi wartościami w innej tabeli. Wydaje się, że ma to dwie wady: najważniejszą z nich jest to, że jedynym sposobem sortowania heterogenicznych typów wcześniejszych wartości w tej samej kolumnie jest użycie znaku binary(max). Po drugie, uważam, że trudniej byłoby użyć takiej struktury podczas wyświetlania użytkownikom poprzednich wersji.

  4. Zrób to samo, co w dwóch poprzednich punktach, ale przechowuj wersje w osobnej bazie danych. Pod względem wydajności może być interesujące, aby uniknąć spowolnienia dostępu do najnowszych wersji poprzez umieszczenie poprzednich wersji w tej samej bazie danych; nadal uważam, że jest to przedwczesna optymalizacja i musi być wykonana tylko wtedy, gdy istnieje dowód, że posiadanie starszych i najnowszych wersji w tej samej bazie danych jest wąskim gardłem.

</tl-dr>


¹ Na przykład niedopuszczalne byłoby przechowywanie zmian w pliku dziennika, tak jak ma to miejsce w przypadku dzienników HTTP i opróżnianie danych z dziennika do bazy danych w nocy, gdy obciążenie serwera jest najniższe. Informacje o różnych wersjach muszą być dostępne natychmiast lub prawie natychmiast; dopuszczalne jest kilka sekund opóźnienia.

² Informacje nie są uzyskiwane bardzo często i tylko przez określoną grupę użytkowników, ale niedopuszczalne byłoby zmuszanie ich do czekania przez 30 sekund na wyświetlenie listy wersji. Ponownie dopuszczalne jest kilka sekund opóźnienia.

Arseni Mourzenko
źródło
3
Istotne: SQL Server Zmień przechwytywanie danych .
Nick Chammas,

Odpowiedzi:

8

Normalnym sposobem rejestrowania kontroli tego rodzaju jest posiadanie tabeli cieni i rejestrowanie zmian za pomocą wyzwalaczy w kontrolowanej tabeli bazowej. Pozostałe tabele można umieścić na innym dysku fizycznym, jeśli jest to konieczne w celu zwiększenia wydajności, i można na nich umieszczać indeksy, jeśli konieczne jest wsparcie szybkiego pobierania danych.

Tabele będą miały mniej więcej taką samą strukturę jak oryginalne tabele, ale będą miały kolumnę daty i godziny, w której nastąpiła zmiana, oraz znacznik określający, czy wiersz został wstawiony, zmieniony czy usunięty. Sekwencjonowanie wersji można wykonać według znacznika czasu.

Daty zmiany można dokonać, ustawiając kolumnę datetime na wartość null za pomocą domyślnej metody getdate (); kolumna użytkownika kontroli przechwyci użytkownika z domyślną kolumną niepustą Suser_Sname (). Zakładając, że rzeczywisty użytkownik jest personifikowany w sesji, przechwyci on tożsamość użytkownika dokonującego zmiany.

Baza danych nie ma możliwości poznania adresu IP łączącego się z serwerem WWW. Aplikacja będzie musiała jawnie przechwycić i zarejestrować adres IP transakcji.

Jeśli masz dużą liczbę tabel, które chcesz skontrolować, możesz użyć metadanych ze słownika danych systemowych do programowego generowania wyzwalaczy.

To rozwiązanie jest zdecydowanie najlepsze z kilku powodów:

  • Przechwytuje wszelkie zmiany w tabeli, nie tylko te wprowadzone przez aplikację.

  • Tabele kontroli można umieścić na innym zestawie dysków, aby zmniejszyć obciążenie operacji we / wy na tabelach podstawowych.

  • Możesz użyć widoku opartego na unii tabeli i tabeli dziennika kontroli, która pokaże całą historię, w tym bieżącą wersję.

  • W razie potrzeby można indeksować tabele dzienników kontroli, aby użytkownicy audytu mogli odpowiadać na nie w odpowiedzi. Jak zwykle, wybór indeksu jest kompromisem między wydajnością zapytań a kosztem aktualizacji.

ConcernedOfTunbridgeWells
źródło
próbujesz powiedzieć, jeśli mam tabelę 1000, którą muszę prowadzić dziennik dla każdej zmiany, to muszę utworzyć 1000 tabeli cieni, co? i 1000 wyzwalacza do uchwycenia zmiany? jeśli tak, to fałszywy pomysł ... możemy stworzyć pojedynczą tabelę historii i pojedynczy wyzwalacz do przechwytywania i rejestrowania zmienionych danych. możemy przechowywać stare i nowe dane wierszy w tej tabeli jako xml .... to znaczy, że wiele osób robi to ... jestem czysty !!
Thomas
1
Dla 1000 tabel piszesz narzędzie, które odczytuje definicje ze słownika danych systemowych i generuje wyzwalacze i definicje tabel. Zrobiłem to w systemie z 560 stołami i działa dobrze.
ConcernedOfTunbridgeWells
0

Znam wiele systemów CMS (w tym Wordpress), które używają jednej tabeli do przechowywania wszystkich wersji danych. Ale z drugiej strony muszą to zrobić tylko dla tabeli, która zawiera posty na blogu. Zobacz strukturę bazy danych Wordpress .

Również liczba rekordów i liczba poprawek w każdym wierszu będzie odgrywać znaczącą rolę w podejmowaniu decyzji.

Dharmendar Kumar „DK”
źródło
0

O wersjach CMS; dla drupal tworzy specjalną tabelę dla każdego pola encji, która przechowuje starą wartość; taka koncepcja pozwala na precyzyjne manipulowanie danymi, ale myślę, że to drogie, moim własnym rozwiązaniem jest konwersja mojego obiektu do formatu xml i zapisanie go jako łańcucha z innymi polami (changetime, id ...)

Bourkadi
źródło