Cla*_*ash 5 mysql database foreign-keys
希望你们新年快乐.
所以,我的问题是,记录行动的最佳方式是什么.让我用一个例子解释一下,假设我们有这些实体:
User
Friend (用户是另一个用户的朋友,多对多关系)
Message (用户可以向其他用户发送消息)
Group (用户可以在不同的组中)
Game (游戏可以与各种玩家一起玩,有一些信息,如游戏日期.这导致两个故事,游戏和游戏用户,后者存储用户和游戏之间的关系)
现在,我想制作一个日志,例如:
用户A(链接到用户)成为新朋友,用户B(链接到用户)
用户A(链接到用户),B(链接到用户)和C(链接到用户)玩游戏(链接到游戏)
用户C(链接到用户)加入了一个组D(链接到组)
所以,我想制作一个灵活的日志,可以存储我想要的多个引用和对不同实体(例如用户和游戏)的引用.
我知道有两种方法,但它们都有一个或多个问题:
记录动作时,我直接存储我想要的纯文本(即:只有1个char字段,用于存储'用户C加入组').但是,这样有一个问题,这个文本需要翻译成其他语言,我不能为每种语言都有一个字段.
有一个主表log,每行代表一个日志动作和一个代码,所以我知道哪个动作是,即:一个用户加入了一个组,x个用户玩了一个游戏.然后我会为每个需要的外键类型的另一个表,所以我有log_user,log_group和log_game例如,log_user与现场参考log和另一参考user.这样我可以让多个用户进行相同的日志操作.问题:相当复杂并且可能导致大量开销,因为我必须查询多个表的日志操作.这是正确的,它是否会过于密集?
所以,我愿意接受新的想法和头脑风暴.这种问题的最佳方法是什么?在此先感谢,我希望我已经明确地解释了它.如果有任何问题,请询问.
编辑:我决定开始赏金,因为我对收到的答案并不满意.如果需要,将做出任何澄清.谢谢
我想要一些非常类似于facebook/orkut /社交网络"朋友更新"的东西.这将显示给用户.
以下是我将如何做到这一点。在您看到架构后,我在底部还有一些评论。
日志
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 更容易,因为我们需要一个(可能非常快)子查询。
| 归档时间: |
|
| 查看次数: |
1005 次 |
| 最近记录: |