Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Datenbanken:Aktionen protokollieren, wie geht man mit verschiedenen Referenzen um?

Das Folgende ist, wie ich es machen würde. Ich habe unten noch ein paar Kommentare, nachdem Sie das Schema gesehen haben.

Protokollieren

LogID - eindeutige Protokoll-ID

Zeit - Datum/Uhrzeit des Ereignisses

LogType – String oder ID

(Nebenbemerkung, ich würde hier eine ID verwenden, damit Sie eine unten gezeigte Nachrichtentabelle verwenden können, aber wenn Sie schnell und schmutzig wollen, können Sie einfach eine eindeutige Zeichenfolge für jede Protokollzeit eingeben (z. B. "Spiel gestartet", "Nachricht gesendet") , usw.)

LogActor

LogID - externer Schlüssel

LogActorType – String oder ID (wie oben, wenn ID eine Nachschlagetabelle benötigt)

LogActorID – Dies ist eine eindeutige ID für die Tabelle für den Typ, z. B. Benutzer, Gruppe, Spiel

Sequenz - dies ist eine Reihenfolge der Akteure.

Protokollnachricht

LogType - externer Schlüssel

Nachricht - lange Zeichenfolge (varchar(max)?)

Sprache - Zeichenfolge (5), damit Sie verschiedene Sprachen eingeben können, zB "US-en"

Beispieldaten (unter Verwendung Ihrer 3 Beispiele)

Protokoll

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

Protokollnachricht

LogType Message 
1       {0} Made a new friend {1}
2       {0}, {1}, {2} played a game ({3})
3       {0} joined a group ({1})

Benutzer

ID Name
1  User A
2  User B
3  User C

Spiel

ID Name
1  Name of game

Gruppe

ID Name
1  Name of group

Hier sind also die schönen Dinge an diesem Design.

  • Es ist sehr einfach zu erweitern

  • Es behandelt mehrsprachige Probleme unabhängig von den Akteuren

  • Es ist selbstdokumentierend, die LogMessage-Tabelle erklärt genau, was die von Ihnen gespeicherten Daten aussagen sollten.

Einige schlechte Dinge daran.

  • Sie müssen eine komplizierte Verarbeitung durchführen, um die Nachrichten zu lesen.

  • Sie können nicht einfach in die Datenbank schauen und sehen, was passiert ist.

Meiner Erfahrung nach überwiegen die guten Seiten eines solchen Designs die schlechten Seiten. Um mir einen schnellen und schmutzigen Blick auf das Protokoll zu ermöglichen, habe ich eine Ansicht erstellt (die ich nicht für den Anwendungscode verwende), die ich mir ansehen kann, wenn ich sehen muss, was über die Rückseite vor sich geht Ende.

Lassen Sie mich wissen, wenn Sie Fragen haben.

Update – Einige Beispielabfragen

Alle meine Beispiele sind in sqlserver 2005+, lassen Sie mich wissen, wenn es eine andere Version gibt, auf die ich abzielen soll.

Zeigen Sie die LogActor-Tabelle an (es gibt eine Reihe von Möglichkeiten, dies zu tun, die beste hängt von vielen Dingen ab, einschließlich Datenverteilung, Anwendungsfällen usw.) Hier sind zwei:

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

Im Allgemeinen denke ich, dass a) besser ist als b) Wenn Sie beispielsweise einen Akteur vermissen, geben Sie a) ein (mit einem Nullnamen). b) ist jedoch einfacher zu pflegen (weil die UNION ALL-Anweisungen es modularer machen). Es gibt andere Möglichkeiten, dies zu tun (z. B. CTE, Ansichten usw.). Ich neige dazu, es wie b) zu machen, und nach dem, was ich gesehen habe, scheint das zumindest Standardpraxis, wenn nicht Best Practice zu sein.

Die letzten 10 Elemente im Protokoll würden also etwa so aussehen:

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 - Wie Sie sehen können, ist es einfacher, alle Protokolleinträge eines Datums als das letzte X auszuwählen, da wir dafür eine (wahrscheinlich sehr schnelle) Unterabfrage benötigen.