以下は私がそれを行う方法です。スキーマを見た後、下部にもう少しコメントがあります。
ログ
LogID-一意のログID
時間-イベントの日付/時間
LogType-文字列またはID
(サイドコメント、ここではIDを使用して、以下に示すメッセージテーブルを使用できるようにしますが、クイックnダーティが必要な場合は、ログ時間ごとに一意の文字列を使用できます(例:「ゲーム開始」、「メッセージ送信」)。 、など)
LogActor
LogID-外部キー
LogActorType-文字列またはID(上記のように、IDの場合はルックアップテーブルが必要になります)
LogActorID-これは、ユーザー、グループ、ゲームなどのタイプのテーブルに対する一意のIDです
シーケンス-これはアクターの順序です。
LogMessage
LogType-外部キー
メッセージ-長い文字列(varchar(max)?)
言語-string(5)なので、「US-en」などの別の言語をキーオフできます
サンプルデータ(3つの例を使用)
ログ
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})
ユーザー
ID Name
1 User A
2 User B
3 User C
ゲーム
ID Name
1 Name of game
グループ
ID Name
1 Name of group
ですから、このデザインの良いところは次のとおりです。
-
拡張は非常に簡単です
-
アクターに関係なく多言語の問題を処理します
-
これは自己文書化であり、LogMessageテーブルは、保存しているデータが何を言うべきかを正確に説明しています。
それについてのいくつかの悪いこと。
-
メッセージを読むには、複雑な処理を行う必要があります。
-
DBを見て、何が起こったのかを確認することはできません。
私の経験では、この種の設計の良い部分は悪い部分を上回っています。ログをすばやく汚く見ることができるようにするために私が行ったことは、背面から何が起こっているかを確認する必要があるときに表示できるビュー(アプリケーションコードには使用しません)を作成することです。終了します。
ご不明な点がありましたらお知らせください。
更新-クエリの例
私の例はすべてsqlserver2005+にあります。ターゲットにしたい別のバージョンがあるかどうか、お知らせください。
LogActorテーブルを表示します(これを行うにはいくつかの方法がありますが、最適な方法は、データの配布、ユースケースなど、多くのことに依存します)ここに2つあります:
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
一般に、a)はb)よりも優れていると思います。たとえば、アクタータイプがない場合は、a)それを(null名で)含めます。ただし、b)は保守が簡単です(UNION ALLステートメントによってモジュール化が進むため)。これを行う方法は他にもあります(CTE、ビューなど)。私はb)のようにそれを行う傾向があり、私が見たところ、それはベストプラクティスではないにしても少なくとも標準的なプラクティスのようです。
したがって、ログの最後の10項目は次のようになります。
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
注意-ご覧のとおり、これには(おそらく非常に高速な)サブクエリが必要なため、最後のXよりも日付からすべてのログアイテムを選択する方が簡単です。