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.