数据库:记录操作,如何处理各种引用?

Cla*_*ash 5 mysql database foreign-keys

希望你们新年快乐.

所以,我的问题是,记录行动的最佳方式是什么.让我用一个例子解释一下,假设我们有这些实体:

User

Friend (用户是另一个用户的朋友,多对多关系)

Message (用户可以向其他用户发送消息)

Group (用户可以在不同的组中)

Game (游戏可以与各种玩家一起玩,有一些信息,如游戏日期.这导致两个故事,游戏和游戏用户,后者存储用户和游戏之间的关系)

现在,我想制作一个日志,例如:

  1. 用户A(链接到用户)成为新朋友,用户B(链接到用户)

  2. 用户A(链接到用户),B(链接到用户)和C(链接到用户)玩游戏(链接到游戏)

  3. 用户C(链接到用户)加入了一个组D(链接到组)

所以,我想制作一个灵活的日志,可以存储我想要的多个引用和对不同实体(例如用户和游戏)的引用.

我知道有两种方法,但它们都有一个或多个问题:

  1. 记录动作时,我直接存储我想要的纯文本(即:只有1个char字段,用于存储'用户C加入组').但是,这样有一个问题,这个文本需要翻译成其他语言,我不能为每种语言都有一个字段.

  2. 有一个主表log,每行代表一个日志动作和一个代码,所以我知道哪个动作是,即:一个用户加入了一个组,x个用户玩了一个游戏.然后我会为每个需要的外键类型的另一个表,所以我有log_user,log_grouplog_game例如,log_user与现场参考log和另一参考user.这样我可以让多个用户进行相同的日志操作.问题:相当复杂并且可能导致大量开销,因为我必须查询多个表的日志操作.这是正确的,它是否会过于密集?

所以,我愿意接受新的想法和头脑风暴.这种问题的最佳方法是什么?在此先感谢,我希望我已经明确地解释了它.如果有任何问题,请询问.

编辑:我决定开始赏金,因为我对收到的答案并不满意.如果需要,将做出任何澄清.谢谢

我想要一些非常类似于facebook/orkut /社交网络"朋友更新"的东西.这将显示给用户.

Hog*_*gan 5

以下是我将如何做到这一点。在您看到架构后,我在底部还有一些评论。

日志

LogID - 唯一的日志 ID

时间 - 事件的日期/时间

LogType - 字符串或 ID

(旁注,我会在这里使用一个 id,这样你就可以使用下面显示的消息表,但是如果你想快速变脏,你可以只为每个日志时间设置一个唯一的字符串(例如“游戏开始”、“消息发送”) , 等等)

日志Actor

LogID - 外部密钥

LogActorType - 字符串或 ID(如上,如果 ID,您将需要查找表)

LogActorID - 这是表的唯一 ID,类型为用户、组、游戏

序列 - 这是演员的顺序。

日志消息

LogType - 外部键

消息 - 长字符串(varchar(max)?)

语言 - 字符串(5),因此您可以关闭不同的语言,例如“US-en”

示例数据(使用您的 3 个示例)

日志

ID  Time   LogType 
1   1/1/10 1
2   1/1/10 2
3   1/1/10 3
Run Code Online (Sandbox Code Playgroud)

日志Actor

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
Run Code Online (Sandbox Code Playgroud)

日志消息

LogType Message 
1       {0} Made a new friend {1}
2       {0}, {1}, {2} played a game ({3})
3       {0} joined a group ({1})
Run Code Online (Sandbox Code Playgroud)

用户

ID Name
1  User A
2  User B
3  User C
Run Code Online (Sandbox Code Playgroud)

游戏

ID Name
1  Name of game
Run Code Online (Sandbox Code Playgroud)

团体

ID Name
1  Name of group
Run Code Online (Sandbox Code Playgroud)

所以这里是关于这个设计的好东西。

  • 很容易扩展

  • 它处理独立于参与者的多语言问题

  • 它是自我记录的,LogMessage 表准确地解释了您存储的数据应该说什么。

关于它的一些不好的事情。

  • 您必须进行一些复杂的处理才能读取消息。

  • 你不能只看数据库就知道发生了什么。

根据我的经验,这种设计的好部分超过了坏部分。为了让我快速查看日志,我所做的是创建一个视图(我不用于应用程序代码),当我需要通过背面查看正在发生的事情时,我可以查看它结尾。

如果您有任何疑问,请告诉我。

更新 - 一些示例查询

我的所有示例都在 sqlserver 2005+ 中,如果您希望我针对不同的版本,请告诉我。

查看 LogActor 表(有很多方法可以做到这一点,最好的取决于很多事情,包括数据分布、用例等)这里有两个:

一种)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

一般来说,我认为 a) 比 b) 好,例如,如果您缺少一个演员类型 a) 将包括它(名称为空)。但是 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
Run Code Online (Sandbox Code Playgroud)

注意 - 如您所见,从日期中选择所有日志项比最后一个 X 更容易,因为我们需要一个(可能非常快)子查询。