2009-04-17 25 views
48

Przeczytałem kilka pytań na temat SO (takich jak this one) w odniesieniu do wersjonowania danych w bazie danych.Baza danych - wersja danych

Podobały mi się niektóre z sugestii, które zostały wymienione. Mam najdłużej potrzebny (potrzebny) przegląd wielu moich stołów, ale nigdy się do tego nie zbliżyłem. Będąc programistą, który ma za sobą tylko prostą pracę z bazami danych, zastanawiałem się, jak można to zrobić.

Nie proszę o rzeczywiste rozwiązanie w składni SQL. W końcu mogę to sobie wyobrazić (lub wysłać pocztą SO, gdy nadejdzie czas). Po prostu proszę ludzi, aby komentowali, w jaki sposób zamierzają to zrobić, a wszelkie potencjalne problemy z wydajnością mogą wystąpić, gdybym "poprawił" setki milionów rekordów. Lub inne sugestie, o ile opiera się na przykładzie poniżej.

Biorąc prosty przykład:

Person 
------------------------------------------------ 
ID    UINT NOT NULL, 
PersonID   UINT NOT NULL, 
Name    VARCHAR(200) NOT NULL, 
DOB    DATE NOT NULL, 
Email    VARCHAR(100) NOT NULL 

Audit 
------------------------------------------------ 
ID    UINT NOT NULL, 
UserID   UINT NOT NULL,    -- Who 
TableName   VARCHAR(50) NOT NULL,  -- What 
OldRecID   UINT NOT NULL,    -- Where 
NewRecID   UINT NOT NULL, 
AffectedOn  DATE NOT NULL,    -- When 
Comment   VARCHAR(500) NOT NULL  -- Why 

Nie jestem pewien, w jaki sposób można by połączyć tabelę Audytu do innych tabel (takich jak osoby) jeżeli TableName jest ciągiem?

Ponadto, zakładając, że mam trzy GUI do wypełnienia:

  1. pełny zapis dla osoby konkretnym identyfikatorze
  2. widoku tabeli wykaz wszystkich osób (wg ID)
  3. widok pokazujący każdą osobę z informacjami o ich zmianach pod każdym wpisem (liczba poprawek na osobę, daty korekt, komentarze do wersji itp.) uporządkowanymi według najnowszych wersji.

Aby zrealizować 1 i 2, czy byłoby lepiej zapytać o tabelę Person lub tabelę Audytu?

Czy w celu osiągnięcia 3, tak zwany ekspert bazy danych po prostu pobierze wszystkie rekordy i przekaże je oprogramowaniu do przetworzenia lub pogrupie według identyfikatora PersonID i daty wpływu? Czy jest to zwykle obsługiwane w jednym zapytaniu lub wielu?

+0

audytu jest mało prawdopodobne, aby komentarz był używany dużo, chyba że automatycznie go zapełnisz. –

Odpowiedz

42

Zrobiłem różnych systemów kontrolnych na przestrzeni lat i jestem obecnie zamiar zaimplementować coś takiego:

Person 
------------------------------------------------ 
ID    UINT NOT NULL, 
PersonID   UINT NOT NULL, 
Name    VARCHAR(200) NOT NULL, 
DOB    DATE NOT NULL, 
Email    VARCHAR(100) NOT NULL 


Person_History 
------------------------------------------------ 
ID    UINT NOT NULL, 
PersonID   UINT NOT NULL, 
Name    VARCHAR(200) NOT NULL, 
DOB    DATE NOT NULL, 
Email    VARCHAR(100) NOT NULL 
AuditID   UINT NOT NULL 


Audit 
------------------------------------------------ 
ID    UINT NOT NULL, 
UserID   UINT NOT NULL,    -- Who 
AffectedOn  DATE NOT NULL,    -- When 
Comment   VARCHAR(500) NOT NULL  -- Why 

Obecne zapisy są zawsze w tabeli osoby. Jeśli występuje zmiana, tworzony jest rekord audytu, a stary rekord jest kopiowany do tabeli Person_History (zauważ, że identyfikator nie zmienia się i może występować wiele wersji)

Identyfikator audytu znajduje się w tabelach * _Historia, dzięki czemu można link wielu zmian rekordów do jednego rekordu kontroli, jeśli chcesz.

EDIT:
Jeśli nie masz osobną tabelę historia dla każdej tabeli bazowej i chcesz używać tej samej tabeli trzymać „usunięte” stare rekordy i to trzeba zaznaczyć rekordy z flagą stanu. Problem z tym, że jest to prawdziwy problem podczas sprawdzania aktualnych rekordów - uwierz mi, że to zrobiłem.

+1

Dzięki za odpowiedź! Tak to sobie wyobraziłem na początku, ale ponieważ mam ponad 100 tabel do korekty, chciałem uniknąć również posiadania 100 tabel rewizyjnych i 100 tablic kontrolnych. Właśnie dlatego próbowałem udostępnić tabelę kontroli we wszystkich moich tabelach, a także uniknąć powielania każdej tabeli. Może mój cel jest nieuzasadniony, ale właśnie dlatego badam i badam na ten temat. Jeszcze raz dzięki! – Jeach

+10

+1 dla tabeli historii dla tabeli bazowej. Często istnieje chęć posiadania jednego stołu kontroli.Może to prowadzić do poważnych problemów z wydajnością, jeśli system jest dość zajęty. Tabela kontroli staje się wąskim gardłem dla każdej transakcji. Po prostu jeśli transakcja # 2 czeka na zakończenie transkrypcji nr 1, Twój użytkownik będzie odczuwał spowolnienie – Karl

+1

Potrzebujesz tylko jednej tabeli kontroli - ale nadal potrzebujesz tabeli historii dla każdej z głównych tabel –

2

Obserwując posta DJa przy użyciu tabeli historii na stół bazowy i komentarz Karl'a na temat możliwych problemów z wydajnością, wykonałem trochę badań SQL, aby znaleźć najszybszy sposób przeniesienia rekordu z jednej tabeli do innego.

Chciałem udokumentować co znalazłem:

myślałem, że będę musiał zrobić SQL sprowadzić do załadowania rekordu z tabeli podstawowej, a następnie z naciśnięciem SQL umieścić zapis do tabeli historii , a następnie aktualizacja do tabeli podstawowej w celu wstawienia zmienionych danych. Razem 3 transakcje.

Jednak ku mojemu zaskoczeniu zdałem sobie sprawę, że możesz wykonać dwie pierwsze transakcje, używając jednej instrukcji SQL, używając składni SELECT INTO. Założę się, że wydajność będzie sto razy szybsza.

Następnie pozwoliłoby to nam po prostu zaktualizować rekord z nowymi danymi w tabeli podstawowej.

Nadal nie znalazłem jednej instrukcji SQL, aby wykonać wszystkie 3 transakcje naraz (wątpię, że to zrobię).

+0

Nie znajdziesz pojedynczego wyciągu do zrobienia wszystkiego naraz. Możesz symulować trzy jednocześnie za pomocą transakcji lub punktu zapisu. –

+0

Przykład Sql byłby bardzo doceniany – Jowen

5

Powinieneś utworzyć tabelę jak zwykle, mieć kolumnę ModifiedDate na każdym rekordzie (i ModifiedBy, jeśli chcesz) i robić wszystkie dane dostępu poprzez zmaterializowany widok, który grupuje dane według Id, a następnie robi HAVING ModifiedDate = MAX (ModifiedDate)?

W ten sposób dodanie nowego rekordu o tym samym identyfikatorze co inny spowoduje usunięcie starego rekordu z widoku. Jeśli chcesz zapytać o historię, nie przeglądaj widoku

Zawsze uważałem, że utrzymywanie różnych tabel z tymi samymi kolumnami jest skomplikowane i podatne na błędy.

+0

Eksperymentowałem z tym, co proponowałeś używając MySQL. Wiem, że jest to wykonalne (teoretycznie i wydaje się dość skuteczne). Problem polega na tym, że MySQL (próbowałem kilku wersji) ma poważne błędy z jego widokami (subquries, sort, order, etc). To poważny problem w @ $$. – Jeach

+0

Jaka jest twoja strategia z indeksami klastrowanymi na stole? – JoeBrockhaus

+0

Nie wiem, to podejście było tylko eksperymentem myślowym! – mcintyre321

0

Podoba mi się twoja tabela kontroli, to dobry początek. Masz problem ze swoim tabeli liczności audytu, więc chciałbym psuć go jako dwóch tabelach:

Person 
------------------------------------------------ 
ID    UINT NOT NULL, 
PersonID   UINT NOT NULL, 
Name    VARCHAR(200) NOT NULL, 
DOB    DATE NOT NULL, 
Email    VARCHAR(100) NOT NULL, 
AuditID   UINT NOT NULL 

Audit 
------------------------------------------------ 
ID    UINT NOT NULL, 
TableName   VARCHAR(50) NOT NULL,  -- What 
TableKey   UINT NOT NULL, 
CreateDate  DATETIME NOT NULL DEFAULT(NOW), 
CreateUserID  UINT NOT NULL, 
ChangeDate  DATETIME NOT NULL DEFAULT(NOW), 
ChangeUserID  UINT NOT NULL 

Audit_Item 
------------------------------------------------ 
ID    UINT NOT NULL, 
AuditID   UINT NOT NULL,    -- Which audit record 
UserID   UINT NOT NULL,    -- Who 
OldRecID   UINT NOT NULL,    -- Where 
NewRecID   UINT NOT NULL, 
AffectedOn  DATE NOT NULL,    -- When 
Comment   VARCHAR(500) NOT NULL  -- Why 

Początkowy układ zaproponowany posiada pojedynczy rekord audytu, który wskazuje z powrotem (zakładam) dwóch rejestrów osób. Wyzwania związane z tym projektem są następujące:

  • Jakie zapisy w tabeli osób są aktualnymi "prawdziwymi" rekordami?
  • Jak przedstawiasz całą historię zmian w rekordzie osoby? Jeśli wskazujesz dwa wpisy w tabeli Osoby, zobacz punkt # 1: , który z nich jest bieżącym rekordem?
  • Pola Utwórz *, zmień * są zwinięte z kolekcji rekordów Audit_Item . Są one dostępne tylko dla ułatwienia dostępu.
  • Kluczem AuditID w tabeli Osoba pozwala wskazać powrotem do stołu Audytu i dostać się do historię osoba fizyczna bez konieczności kwerendy tabeli Audytu z klauzulą ​​WHERE TableName='Person'
+0

Przez jakiś czas wpatrywałam się w twój problem liczności i po prostu nie rozumiem Twoich zamierzonych korzyści? Czy to nie są identyfikatory UserID, CreateUserID i ChangeUserID tych samych informacji? Czy nie wpływa również na duplikaty ?, CreateDate i ChangeDate? Alos, czy to nie jest kolejna transakcja SQL za każdym razem, gdy ktoś jest edytowany? Czy możesz edytować swój wpis, aby wyjaśnić proponowane ulepszenie ... dzięki! – Jeach

+1

Myślę, że źle zrozumiałeś proces Akceptowanej odpowiedzi. W tabeli Osoba będzie tylko jeden rekord Osoby. Będzie wiele wierszy Person_History. Audit wskazuje na wiele Person_History, ale wszystkie wskazują na jedną osobę. Osoba jest "aktualna", każda osoba_Historia jest poprzednią wersją. – JoeBrockhaus