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 SQLfilestream
, - 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:
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ę.
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
null
nie jest rozwiązaniem, ponieważ muszę także śledzić, kiedy wartość jest zmieniana nanull
lub znull
.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.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.