草庐IT

mysql - 数据库: Making a Log of actions,如何处理各种引用?

coder 2023-10-04 原文

希望大家新年快乐。

所以,我的问题是,制作操作日志的最佳方式是什么。让我用一个例子来解释它,假设我们有这些实体:

用户

friend (用户是另一个用户的 friend ,多对多关系)

消息(一个用户可以向另一个用户发送消息)

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

游戏(一个游戏可以和不同的玩家一起玩,有一些信息,比如游戏日期。这会产生两个故事,games 和 games_users,后者存储用户和游戏之间的关系)

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

  1. 用户 A(用户链接)交了新 friend 用户 B(用户链接)

  2. 用户 A(链接到用户)、B(链接到用户)和 C(链接到用户)玩了一个游戏(链接到游戏)

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

因此,我想制作一个灵活的日志,它可以存储任意数量的引用以及对不同实体(例如用户和游戏)的引用。

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

  1. 记录一个 Action 时,我直接存储我想要的纯文本(即:只有 1 个字符字段,它将存储“用户 C 加入了一个组”)。但是,这种方式存在一个问题,该文本需要翻译成其他语言,我不能为每种语言设置一个字段。

  2. 有一个主表log,其中每一行代表一个日志操作和一个代码,所以我知道那是哪个操作,即:一个用户加入了一个组,x 个用户玩了一个游戏.然后我为每个需要的外键类型创建了另一个表,所以我有 log_userlog_grouplog_game 例如,log_user,其中一个字段引用 log,另一个字段引用 user。这样我就可以让多个用户执行同一个日志操作。问题:相当复杂,并且可能会导致大量开销,这取决于我必须查询多个表的日志操作。这是否正确,会不会太占用 CPU 资源?

因此,我乐于接受新想法和集思广益。解决此类问题的最佳方法是什么? 在此先感谢,我希望我已经清楚地解释了它。如有任何问题,请提问。

编辑:我决定开始悬赏,因为我对收到的答案不是很满意。如果需要,将作出任何澄清。谢谢

我想要与 facebook/orkut/社交网络“ friend 更新”非常相似的东西。这将显示给用户。

最佳答案

下面是我会怎么做。 在您看到架构后,我在底部有更多评论。

日志

LogID - 唯一的日志 ID

Time - 事件的日期/时间

日志类型 - 字符串或 ID

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

LogActor

LogID - 外键

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

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

序列 - 这是 Actor 的顺序。

日志消息

LogType - 外部 key

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

Language - string(5) 这样你就可以关闭不同的语言,例如“US-en”

示例数据 (使用你的 3 个例子)

日志

ID  Time   LogType 
1   1/1/10 1
2   1/1/10 2
3   1/1/10 3

日志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

日志消息

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

下面是这个设计的优点。

  • 很容易扩展

  • 它处理多语言问题 独立于 Actor

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

关于它的一些坏处。

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

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

根据我的经验,这种设计的好处多于坏处。为了让我快速查看日志,我做了一个 View (我不将其用于应用程序代码),当我需要通过后台查看发生了什么时,我可以查看该 View 结束。

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

更新 - 一些示例查询

我的所有示例都在 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

二)

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) 好,例如,如果您缺少一个 actor,则类型 a) 将包含它(使用空名称)。但是 b) 更易于维护(因为 UNION ALL 语句使其更加模块化。)还有其他方法可以做到这一点(例如 CTE、 View 等)。我倾向于像 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 更容易,因为为此我们需要一个(可能非常快的)子查询。

关于mysql - 数据库: Making a Log of actions,如何处理各种引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1989100/

有关mysql - 数据库: Making a Log of actions,如何处理各种引用?的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  3. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  4. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  5. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  6. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  7. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  8. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  9. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  10. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

随机推荐