Mysql
 sql >> Base de données >  >> RDS >> Mysql

Bases de données :Réaliser un journal des actions, comment gérer les différentes références ?

Voici comment je procéderais. J'ai d'autres commentaires en bas après avoir vu le schéma.

Journal

LogID - ID de journal unique

Heure - date/heure de l'événement

LogType - Chaîne ou ID

(commentaire latéral, j'irais avec un identifiant ici pour que vous puissiez utiliser un tableau de messages ci-dessous, mais si vous voulez rapide et sale, vous pouvez juste une chaîne unique pour chaque heure de journal (par exemple "Game Started", "Message Sent" , etc.)

LogActor

LogID - clé externe

LogActorType - Chaîne ou ID (comme ci-dessus, si l'ID vous aurez besoin d'une table de recherche)

LogActorID - Il s'agit d'un identifiant unique dans la table pour le type, par exemple Utilisateur, Groupe, Jeu

Séquence - c'est un ordre des acteurs.

LogMessage

LogType - clé externe

Message - chaîne longue (varchar(max) ?)

Langue - chaîne (5) pour que vous puissiez saisir différentes langues, par exemple "US-en"

Exemple de données (en utilisant vos 3 exemples)

Journal

ID  Time   LogType 
1   1/1/10 1
2   1/1/10 2
3   1/1/10 3

LogActeur

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

JournalMessage

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

Utilisateur

ID Name
1  User A
2  User B
3  User C

Jeu

ID Name
1  Name of game

Groupe

ID Name
1  Name of group

Voici donc les avantages de ce design.

  • Il est très facile d'étendre

  • Il gère les problèmes multilingues indépendamment des acteurs

  • Il s'auto-documente, la table LogMessage explique exactement ce que les données que vous stockez doivent dire.

Quelques mauvaises choses à ce sujet.

  • Vous devez faire un traitement compliqué pour lire les messages.

  • Vous ne pouvez pas simplement regarder la base de données et voir ce qui s'est passé.

D'après mon expérience, les bons côtés de ce type de conception l'emportent sur les mauvais côtés. Ce que j'ai fait pour me permettre de jeter un coup d'œil rapide et sale au journal est de créer une vue (que je n'utilise pas pour le code d'application) que je peux regarder quand j'ai besoin de voir ce qui se passe via le dos fin.

Faites-moi savoir si vous avez des questions.

Mise à jour – Quelques exemples de requêtes

Tous mes exemples sont dans sqlserver 2005+, faites-moi savoir s'il y a une version différente que vous voulez que je cible.

Affichez la table LogActor (il existe plusieurs façons de procéder, la meilleure dépend de nombreux facteurs, notamment la distribution des données, les cas d'utilisation, etc.) En voici deux :

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

En général, je pense que a) est meilleur que b) Par exemple, s'il vous manque un type d'acteur, a) l'inclura (avec un nom nul). Cependant, b) est plus facile à maintenir (parce que les instructions UNION ALL le rendent plus modulaire.) Il existe d'autres façons de le faire (par exemple, CTE, vues, etc.). Je suis enclin à le faire comme b) et d'après ce que j'ai vu, cela semble être au moins une pratique standard, sinon une meilleure pratique.

Ainsi, les 10 derniers éléments du journal ressembleraient à ceci :

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 - Comme vous pouvez le voir, il est plus facile de sélectionner tous les éléments de journal à partir d'une date que le dernier X, car nous avons besoin d'une sous-requête (probablement très rapide) pour cela.