Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Bazy danych:Tworzenie dziennika działań, jak obsługiwać różne referencje?

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP/mysql:jak wyświetlić rekordy posortowane według czasu i pogrupowane według daty?

  2. Jak uzyskać ostatni dzień miesiąca w mysql, podając miesiąc i rok jako dane wejściowe?

  3. Nieskończona pętla PHP while

  4. złożone zamówienie sql przez

  5. W MySQL 5 SELECT COUNT(1) FROM nazwa_tabeli działa bardzo wolno