Oto, jak bym to zrobił. Mam więcej komentarzy na dole po obejrzeniu schematu.
Dziennik
LogID - unikalny identyfikator dziennika
Czas - data/czas wydarzenia
LogType — ciąg znaków lub identyfikator
(komentarz boczny, wybrałbym tutaj id, więc możesz użyć tabeli wiadomości pokazanej poniżej, ale jeśli chcesz szybko i brudno, możesz po prostu unikalny ciąg dla każdego czasu logowania (np. "Gra rozpoczęta", "Wiadomość wysłana" itd.)
LogActor
LogID - klucz zewnętrzny
LogActorType - String lub ID (jak wyżej, jeśli ID będziesz potrzebować tabeli przeglądowej)
LogActorID - To unikalny identyfikator tabeli dla typu, np. Użytkownik, Grupa, Gra
Sekwencja - to kolejność aktorów.
Komunikat dziennika
LogType - klucz zewnętrzny
Wiadomość - długi ciąg (varchar(max)?)
Język - ciąg(5), dzięki czemu możesz wyłączyć inny język, np. "US-en"
Przykładowe dane (przy użyciu 3 przykładów)
Dziennik
ID Time LogType
1 1/1/10 1
2 1/1/10 2
3 1/1/10 3
LogActor
LogID LogActorType LogActorID Sequence
1 User 1 1
1 User 2 2
2 User 1 1
2 User 2 2
2 User 2 3
2 Game 1 4
3 User 3 1
3 Group 1 2
LogMessage
LogType Message
1 {0} Made a new friend {1}
2 {0}, {1}, {2} played a game ({3})
3 {0} joined a group ({1})
Użytkownik
ID Name
1 User A
2 User B
3 User C
Gra
ID Name
1 Name of game
Grupa
ID Name
1 Name of group
Oto miłe rzeczy związane z tym projektem.
-
Bardzo łatwo ją rozszerzyć
-
Obsługuje wielojęzyczne problemy niezależnie od aktorów
-
Jest samodokumentujący, tabela LogMessage wyjaśnia dokładnie, co powinny oznaczać przechowywane dane.
Kilka złych rzeczy.
-
Aby odczytać wiadomości, musisz wykonać skomplikowane przetwarzanie.
-
Nie możesz po prostu spojrzeć na DB i zobaczyć, co się stało.
Z mojego doświadczenia wynika, że dobre części tego rodzaju konstrukcji przeważają nad złymi. To, co zrobiłem, aby umożliwić mi szybkie i brudne spojrzenie na dziennik, to utworzenie widoku (którego nie używam do kodu aplikacji), który mogę przeglądać, gdy muszę zobaczyć, co dzieje się z tyłu koniec.
Daj mi znać, jeśli masz pytania.
Aktualizacja – kilka przykładowych zapytań
Wszystkie moje przykłady są w sqlserver 2005+, daj mi znać, jeśli istnieje inna wersja, którą chcesz, abym był celem.
Wyświetl tabelę LogActor (można to zrobić na kilka sposobów, najlepszy zależy od wielu rzeczy, w tym dystrybucji danych, przypadków użycia itp.) Oto dwa:
a)
SELECT
LogId,
COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
Sequence
FROM LogActor A
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence
b)
SELECT
LogId,
U.Name AS Name,
Sequence
FROM LogActor A
INNER JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
UNION ALL
SELECT
LogId,
Ga.Name AS Name,
Sequence
FROM LogActor A
INNER JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
UNION ALL
SELECT
LogId,
Go.Name AS Name,
Sequence
FROM LogActor A
INNER JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
ORDER BY LogID, Sequence
Ogólnie myślę, że a) jest lepsze niż b) Na przykład, jeśli brakuje aktora, typ a) dołączy go (z pustą nazwą). Jednak b) jest łatwiejszy w utrzymaniu (ponieważ instrukcje UNION ALL czynią go bardziej modułowym). Istnieją inne sposoby, aby to zrobić (np. CTE, widoki itp.). Jestem skłonny robić to jak b) iz tego, co widziałem, wydaje się to przynajmniej standardową praktyką, jeśli nie najlepszą praktyką.
Tak więc ostatnie 10 pozycji w dzienniku wyglądałoby mniej więcej tak:
SELECT
LogId,
M.Message,
COLLESCE(U.Name,Ga.Name,Go.Name) AS Name,
Time,
A.Sequence
FROM Log
LEFT JOIN LogActor A ON Log.LogID = A.LogID
LEFT JOIN User U ON A.LogActorID = U.[ID] AND LogActorType = "User"
LEFT JOIN Game Ga ON A.LogActorID = Ga.[ID] AND LogActorType = "Game"
LEFT JOIN Group Go ON A.LogActorID = Go.[ID] AND LogActorType = "Group"
LEFT JOIN LogMessage M ON Log.LogType = M.LogMessage
WHERE LogID IN (SELECT Top 10 LogID FROM Log ORDER BY Date DESC)
ORDER BY Date, LogID, A.Sequence
NB - Jak widać, łatwiej jest wybrać wszystkie elementy dziennika z daty niż ostatniego X, ponieważ potrzebujemy do tego (prawdopodobnie bardzo szybkiego) podzapytania.