O seguinte é como eu faria isso. Eu tenho mais alguns comentários na parte inferior depois de você ter visto o esquema.
Registro
LogID - ID de log exclusivo
Hora - data/hora do evento
LogType - String ou ID
(comentário lateral, eu usaria um id aqui para que você possa usar uma tabela de mensagens mostrada abaixo, mas se você quiser quick n dirty você pode apenas uma string exclusiva para cada tempo de log (por exemplo, "Game Started", "Message Sent" , etc)
LogActor
LogID - chave externa
LogActorType - String ou ID (como acima, se for ID, você precisará de uma tabela de pesquisa)
LogActorID - Este é um id exclusivo para a tabela para o tipo, por exemplo, Usuário, Grupo, Jogo
Sequência - esta é uma ordenação dos atores.
LogMessage
LogType - chave externa
Mensagem - string longa (varchar(max)?)
Idioma - string(5) para que você possa digitar um idioma diferente, por exemplo, "US-en"
Dados de exemplo (usando seus 3 exemplos)
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})
Do utilizador
ID Name
1 User A
2 User B
3 User C
Jogo
ID Name
1 Name of game
Grupo
ID Name
1 Name of group
Então, aqui estão as coisas boas sobre este design.
-
É muito fácil estender
-
Ele lida com questões multilíngue independente dos atores
-
É autodocumentado, a tabela LogMessage explica exatamente o que os dados que você está armazenando devem dizer.
Algumas coisas ruins sobre isso.
-
Você tem que fazer algum processamento complicado para ler as mensagens.
-
Você não pode simplesmente olhar para o banco de dados e ver o que aconteceu.
Na minha experiência, as partes boas desse tipo de design superam as partes ruins. O que eu fiz para me permitir dar uma olhada rápida e suja no log é fazer uma visualização (que eu não uso para o código do aplicativo) que eu possa ver quando precisar ver o que está acontecendo na parte de trás fim.
Deixe-me saber se você tem perguntas.
Atualização - Algumas consultas de exemplo
Todos os meus exemplos estão no sqlserver 2005+, deixe-me saber se há uma versão diferente que você deseja que eu direcione.
Veja a tabela LogActor (Existem várias maneiras de fazer isso, a melhor depende de muitas coisas, incluindo distribuição de dados, casos de uso, etc.) Aqui estão duas:
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
Em geral, acho que a) é melhor que b) Por exemplo, se estiver faltando um ator, digite a) o incluirá (com um nome nulo). No entanto, b) é mais fácil de manter (porque as instruções UNION ALL o tornam mais modular). Existem outras maneiras de fazer isso (por exemplo, CTE, visualizações, etc). Estou inclinado a fazê-lo como b) e pelo que vi isso parece ser pelo menos uma prática padrão, se não a melhor prática.
Então, os últimos 10 itens no log ficariam assim:
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 - Como você pode ver, é mais fácil selecionar todos os itens de log de uma data do que o último X, porque precisamos de uma subconsulta (provavelmente muito rápida) para isso.