Sposoby posiadania historii zmian wpisów w bazie danych

21

Jakie są sposoby, aby umożliwić wersjonowanie wpisów do bazy danych (danych)?

Pomyśl o zdolności systemów zarządzania treścią do cofania zmian artykułów.

Jakie są ich zalety / wady?

matcauthon
źródło
1
Co dokładnie chcesz wersji? Schemat czy dane?
tdammers
1
Chcę zaktualizować dane. Aby pozostać na przykładzie cms, powiedzmy wersje artykułów .
matcauthon,
Możesz zajrzeć do Datomic.
dan_waterworth

Odpowiedzi:

19

Istnieją w zasadzie dwa podejścia: tabela audytu, w której zapisane są wszystkie poprzednie wartości, lub zawierają datę rozpoczęcia / zakończenia jako część tabeli, a wszystkie aktualizacje tworzą nowy rekord podczas zamykania starego.

Aktualizacja: SQL SERVER 2016 obsługuje to jako wzorzec projektowy / typ tabeli - https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2017

jmoreno
źródło
4
Więc pierwsze podejście może być bardziej skalowalne. Ponieważ dane „zarchiwizowane” będą rzadko dostępne, projekt bazy danych można zoptymalizować. A stół roboczy jest mały. W zależności od złożoności powinno być również możliwe zapisywanie tylko różnic. Czy wskazane jest użycie wzorca pamiątkowego ?
matcauthon,
1
Będzie to zależeć od twojego użycia, może być wystarczające użycie wyzwalaczy, aby zapełnić tabelę, a następnie zapewnić sposób wybrania, co i jak daleko do wycofania.
jmoreno
W odpowiedzi masz literówkę (wzór powinien mieć wzór)
geocodezip
7

Jednym z pomysłów jest użycie „baz danych tylko do wstawiania”. Podstawową ideą jest to, że nigdy nie usuwasz ani nie aktualizujesz danych w wierszu .

Każda tabela wymagająca śledzenia będzie miała dwie datetimekolumny fromi to. Zaczynają się od wartości NULLw każdym (od początku do końca czasu). Gdy potrzebujesz „zmienić” wiersz, dodajesz nowy wiersz, a jednocześnie aktualizujesz tow poprzednim wierszu Nowi fromw wierszu, do którego dodajesz Now.

Aby uzyskać bardziej szczegółowe informacje, zobacz:

Ta technika nazywa się AuditTraildo zarządzania starszymi danymi, a jej sklepy zmieniają historię.

Wygląda na to, że pytanie tego rodzaju jest już opublikowane:

Jusubow
źródło
Niestety to pytanie wydaje się usunięte :(
Douglas Gaskell
Nie ma problemu, tutaj jest link . Kolejna dobra propozycja projektu w linku
Yusubov
2

Myślę, że możesz używać wyzwalaczy dla każdej tabeli i utrzymywać dane w _history (lub możesz podać dowolną nazwę), a przy każdej wstawce, aktualizacja, usuwanie w głównej tabeli wyzwoli wyzwalacz i możesz zapisać szczegóły w tej tabeli. jest również dostępny z bazą danych SQLite, jeśli go używasz.

Ten mechanizm jest przydatny również w przypadku dużych projektów. W tej tabeli możesz zapisać informacje o użytkowniku, który dokonał zmian wraz ze znacznikiem czasu zmian. następnie możesz przywrócić tabelę do dowolnego znacznika czasu odpowiadającego Twoim wymaganiom.

Każda baza danych ma swój własny sposób pisania i wyzwalania kodu. Jeśli używasz SQLite, odwiedź SQLite.org, aby uzyskać składnię. W przypadku innych baz danych możesz odwiedzić ich oficjalne strony.

MŚP
źródło
1

Prawdopodobnie znasz silnik db Sqlite . Cały plik db jest zapisany w jednym pliku. Interfejs API obsługuje również wirtualne systemy plików, więc zasadniczo możesz organizować pamięć w dowolnym miejscu i dowolnym formacie, po prostu odpowiadać na operacje odczytu i zapisu przy określonych przesunięciach plików. Możliwe do tego zastosowania mogą być szyfrowanie, kompresja i tak dalej. Najlepsze jest to, że warstwa kontenerowa nie powinna wiedzieć nic o bazach danych, formacie pliku sql lub sqlite, wystarczy stosować się do wywołań zwrotnych xRead i xWrite.

Jednym z pomysłów było wdrożenie funkcji maszyny czasu. Tak więc każda operacja xWrite zapisuje każdy segment, który zastąpiłby w historii „cofania”, a użytkownik może wybrać datę w przeszłości, aby zobaczyć, co zawiera db (prawdopodobnie tryb tylko do odczytu). Nie mam jeszcze działającego przykładu (była dyskusja na ten temat na liście mailowej sqlite), ale prawdopodobnie inne silniki dostarczają API VFS, więc możliwe jest coś podobnego. Po wdrożeniu powinien być kompatybilny ze strukturami baz danych o dowolnej złożoności.

Maksee
źródło
Jak myślisz, co to podejście jest skalowalne dla większych projektów?
matcauthon,
Myślę, że może to zwiększyć obciążenie związane z dużymi danymi w przypadku dużych zmian danych (oczywiście, ponieważ każda zmiana powinna zostać zapisana, chociaż kompresja w przypadku starszych wersji może pomóc). Poza tym z punktu widzenia twojego schematu, tak długo, jak działa dla dwóch tabel, działa dla dwudziestu.
Maksee,
1

Metodą używaną do wersjonowania wpisów w bazie danych jest użycie tabeli kontroli. Tabela ma schemat podobny do:

Seq      - Int      ' Unique identifier for this table
Event    - Char     ' Insert / Update / Delete
TblName  - Char     ' Table that had field value changed
FldName  - Char     ' Field that was changed
KeyValue - Char     ' delimited list of values for fields that make up the PK of table changed
UsrId    - Char     ' User who made the change
OldValue - Char     ' Old value (converted to character)
NewValue - Char     ' New value (converted to character)
AddTs    - DateTime ' When the change was made

Następnie mamy wyzwalacze przy wstawianiu / aktualizowaniu / usuwaniu tabel, które chcemy śledzić.

Plusy:

  • Wszystkie dane są w jednej tabeli
  • Może być skonfigurowany do śledzenia wszystkich pól lub określonych pól w tabeli
  • Łatwe do wyświetlenia wersje dla każdego pola dla tabeli

Cons:

  • Posiadanie wszystkich informacji kontrolnych w jednej tabeli daje bardzo dużą liczbę rekordów
  • Potrzebnych jest wiele wyzwalaczy
briddums
źródło
0

Robię teraz wersję tego. dla każdego rekordu mam wstawioną datę, datę modyfikacji i flagę logiczną rekordu aktywnego. Dla początkowej wstawki Wstawione i zmodyfikowane daty są ustawione na Now () (w tym przykładzie jest Access), a flaga Rekord aktywny jest ustawiona na true. następnie jeśli zmodyfikuję ten rekord, skopiuję całość do nowego rekordu, zmieniając pole (pola), które zmienia użytkownik, pozostawiam wstawioną datę równą oryginałowi i zmieniam Zmodyfikowaną datę na Now (). Następnie odwracam flagę Aktywnego rekordu oryginalnego rekordu do falsei nowego rekordu do true. Mam również pole dla ModifiedRecordsParentID, w którym zapisuję tożsamość oryginalnego rekordu.

Jeśli nawet będę musiał zapytać, mogę po prostu zwrócić rekordy ActiveRecord = truei uzyskać tylko najbardziej aktualne informacje.

Ćwiek
źródło
Nie ma potrzeby ActiveRecordflagi. Wiersz MAX (*) powinien zawsze być bieżącym rekordem. Przywracanie do poprzedniej wersji po prostu wstawia wspomniany wiersz do tabeli.
inwertowanie
Nie byłam pewna, jak sprawić, by wybrane zadziałało, ale teraz, kiedy to wywołujesz, myślę o tym i mam pomysł, hmmmm
Brad
Zwykle MAX (nazwa_kolumny) wybiera największą wartość w kolumnie tabeli. Aby wybrać cały wiersz, wystarczy proste select top 1 order by id descending.
odwrócenie
Tak, to działa na prosty pojedynczy rekord, ale moja tabela była zbiorem rekordów potomnych, które należałoby wybrać od razu, ale można je było modyfikować indywidualnie. Po prostu trochę bardziej skomplikowany.
Brad