Quello che segue è come lo farei. Ho altri commenti in fondo dopo aver visto lo schema.
Registro
LogID - ID registro univoco
Ora - data/ora dell'evento
LogType - Stringa o ID
(commento a lato, andrei con un id qui in modo da poter usare una tabella dei messaggi mostrata di seguito, ma se vuoi quick n dirty puoi solo una stringa univoca per ogni tempo di registro (ad esempio "Game Started", "Message Sent" , ecc)
LogActor
LogID - chiave esterna
LogActorType - Stringa o ID (come sopra, se ID avrai bisogno di una tabella di ricerca)
LogActorID - Questo è un ID univoco per la tabella per il tipo, ad esempio Utente, Gruppo, Gioco
Sequenza:questo è un ordinamento degli attori.
LogMessage
LogType - chiave esterna
Messaggio - stringa lunga (varchar(max)?)
Language - string(5) in modo da poter digitare una lingua diversa, ad esempio "US-en"
Dati di esempio (usando i tuoi 3 esempi)
Registro
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})
Utente
ID Name
1 User A
2 User B
3 User C
Gioco
ID Name
1 Name of game
Gruppo
ID Name
1 Name of group
Quindi ecco le cose belle di questo design.
-
È molto facile da estendere
-
Gestisce questioni multilingua indipendentemente dagli attori
-
È autodocumentante, la tabella LogMessage spiega esattamente cosa dovrebbero dire i dati che stai archiviando.
Alcune cose negative al riguardo.
-
Devi eseguire un'elaborazione complicata per leggere i messaggi.
-
Non puoi semplicemente guardare il DB e vedere cosa è successo.
Nella mia esperienza, le parti buone di questo tipo di design superano le parti negative. Quello che ho fatto per permettermi di dare una rapida occhiata al registro è creare una vista (che non uso per il codice dell'applicazione) che posso guardare quando ho bisogno di vedere cosa sta succedendo dal retro fine.
Fammi sapere se hai domande.
Aggiorna - Alcuni esempi di query
Tutti i miei esempi sono in sqlserver 2005+, fammi sapere se c'è una versione diversa a cui vuoi che miri come target.
Visualizza la tabella LogActor (Esistono diversi modi per farlo, il migliore dipende da molte cose, tra cui la distribuzione dei dati, i casi d'uso, ecc.) Eccone due:
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
In generale penso che a) sia meglio di b) Ad esempio, se ti manca un attore, il tipo a) lo includerà (con un nome nullo). Tuttavia b) è più facile da mantenere (perché le istruzioni UNION ALL lo rendono più modulare). Esistono altri modi per farlo (ad es. CTE, viste, ecc.). Sono propenso a farlo come b) e da quello che ho visto sembra essere almeno una pratica standard se non la migliore pratica.
Quindi, gli ultimi 10 elementi nel registro sarebbero simili a questo:
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 - Come puoi vedere, è più facile selezionare tutti gli elementi di log da una data rispetto all'ultima X, perché per questo abbiamo bisogno di una sottoquery (probabilmente molto veloce).