Mysql
 sql >> Database >  >> RDS >> Mysql

Database:fare un registro delle azioni, come gestire i vari riferimenti?

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).