sql >> Databasteknik >  >> RDS >> Mysql

Databaser:Göra en logg över åtgärder, hur hanterar man olika referenser?

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.



  1. Ska jag använda CASCADE DELETE-regeln?

  2. Byt namn på en mysql-procedur

  3. PHP skriver 800 poster till fil(.txt) från databasen

  4. Hur man formaterar datum och tid i MySQL