Följande är hur jag skulle göra det. Jag har några fler kommentarer längst ner efter att du har sett schemat.
Logg
LogID - unikt logg-ID
Tid – datum/tid för händelsen
LogType - String eller ID
(sidokommentar, jag skulle gå med ett id här så att du kan använda en meddelandetabell som visas nedan, men om du vill ha snabb och smutsig kan du bara bara en unik sträng för varje loggtid (t.ex. "Spel startat", "Meddelande skickat" osv.)
LogActor
LogID - extern nyckel
LogActorType - Sträng eller ID (som ovan, om ID behöver du en uppslagstabell)
LogActorID - Detta är ett unikt ID för tabellen för typen t.ex. Användare, Grupp, Spel
Sekvens - detta är en beställning av skådespelarna.
LogMessage
LogType - extern nyckel
Meddelande - lång sträng (varchar(max)?)
Språk - sträng(5) så att du kan stänga av olika språk t.ex. "US-en"
Exempeldata (med hjälp av dina tre exempel)
Logga
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})
Användare
ID Name
1 User A
2 User B
3 User C
Spel
ID Name
1 Name of game
Grupp
ID Name
1 Name of group
Så här är de fina sakerna med den här designen.
-
Det är mycket lätt att förlänga
-
Den hanterar flerspråkiga frågor oberoende av aktörerna
-
Det är självdokumenterande, LogMessage-tabellen förklarar exakt vad data du lagrar ska säga.
Några dåliga saker med det.
-
Du måste göra en komplicerad bearbetning för att läsa meddelandena.
-
Du kan inte bara titta på DB och se vad som har hänt.
Enligt min erfarenhet uppväger de goda delarna av denna typ av design de dåliga bitarna. Det jag har gjort för att jag ska kunna göra en snabb och smutsig titt på loggen är att göra en vy (som jag inte använder för applikationskoden) som jag kan titta på när jag behöver se vad som händer via baksidan slut.
Hör av dig om du har frågor.
Uppdatering – Några exempelfrågor
Alla mina exempel finns i sqlserver 2005+, låt mig veta om det finns en annan version du vill att jag ska rikta in mig på.
Se LogActor-tabellen (Det finns ett antal sätt att göra detta, det bästa beror på många saker inklusive datadistribution, användningsfall, etc.) Här är två:
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
I allmänhet tycker jag att a) är bättre än b) Om du till exempel saknar en skådespelare kommer typ a) att inkludera den (med ett nollnamn). Men b) är lättare att underhålla (eftersom UNION ALL-satserna gör det mer modulärt.) Det finns andra sätt att göra detta (t.ex. CTE, vyer, etc). Jag är benägen att göra det som b) och av vad jag har sett verkar det vara åtminstone standardpraxis om inte bästa praxis.
Så de sista 10 objekten i loggen skulle se ut ungefär så här:
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
OBS - Som du kan se är det lättare att välja alla loggobjekt från ett datum än det senaste X, eftersom vi behöver en (förmodligen mycket snabb) underfråga för detta.