【问题标题】:How to de-normalize mysql database for user notifications?如何为用户通知去规范化 mysql 数据库?
【发布时间】:2012-03-17 22:56:45
【问题描述】:

我认为有必要为用户通知去规范化数据库。例如,在标记帖子时(应该由用户考虑),我们添加一列flag ENUM('yes', 'no')(或状态列)。可以通过 user_id='XX' AND flag='yes' 的 WHERE 子句计数来为用户查找标记的事件。

这种归一化的结构很好;但是如果我们有不同类型的通知呢?例如帖子,cmets,照片的标志......这意味着当用户刚刚访问他的个人资料页面时,我们需要计算几个表。这对于像 stackexchange 这样的跨项目来说更为严重,因为我们会收到不同站点的通知。

我认为去规范化可以帮助将通知列添加到用户表中

post_flags tinyint(3),
comment_flags tinyint(3),
photo_flags tinyint(3),

在这种情况下,我们需要运行一个额外的写入查询来更新每个相应操作的用户标志列。例如,标记帖子时:UPDATE users SET post_flags=post_flags+1 WHERE user_id='XX'。我关心的是确保执行后一个查询,以避免此数字与标记帖子的计数不匹配;但我认为它可以通过TRANSACTION 保护。

通过这种方式,我们可以通过一次查询频繁访问的个人资料页面获得所有通知。

我在正确的轨道上吗?还是为此目的常用另一种棘手的方法?

【问题讨论】:

  • 你要在tinyint(3) 中存储什么?不是有多个条目吗?
  • 通知的数量。例如,在标记帖子时,我们将运行UPDATE users SET post_flags=post_flags+1 WHERE user_id='XX' 的查询
  • "flag ENUM('yes', 'no')" - 为什么不使用 1 和 0 进行 INT?
  • ENUM 有什么问题?它们都使用相同的存储大小执行相同的操作。
  • 枚举不是 SQL。不同的平台以不同且不兼容的方式支持它。 AFAIK,主流商业 dbms 根本不支持它。 MySQL 和 PostgreSQL 以不同且不兼容的方式支持它。对枚举的更改需要更改架构;对由外键引用相关的表的更改只需要插入一行。 8 Reasons Why MySQL's ENUM Data Type Is Evil 是相关的。

标签: mysql sql normalization denormalization denormalized


【解决方案1】:

使用用户通知表可能会更好。

create table user_notifications (
  user_id integer primary key, -- ? references users, not shown
  post_flags unsigned tinyint(3) not null default 0,
  comment_flags unsigned tinyint(3) not null default 0,
  photo_flags unsigned tinyint(3) not null default 0
);

一个单独的、更窄的表既合乎逻辑又(可能)更快。 Unsigned for flags,因为负数没有意义,而且 MySQL 不强制 CHECK 约束。

就规范化而言,user_notifications 属于 5NF。

【讨论】:

  • 很好的设计,但我不确定是否真的有必要将用户和 user_notifications 分成两列,因为通知可以添加到用户列中。因为它们是tinyint,所以它们在表结构中会很小(甚至有很多通知)。
  • 任何东西都可以添加到“users”表中。那不是问题。您应该问的问题是这些标志是否包含有关用户的信息或其他信息。显而易见的答案是它们包含有关其他事物的信息。 (有关通知的信息。)因此从逻辑上讲,它们属于不同的表。那个更窄的表可以让更多的行放在一个页面上,所以你需要从磁盘读取更少的页面——可能会少很多个页面。这意味着“更快”。 (在我的沙箱中,选择一行空缓存的速度大约快 1000 倍——0.05 毫秒对 34.5 毫秒。)
【解决方案2】:

这是反规范化吗?看起来创建这三个列是一种更好的组织方式,并且对我来说似乎更正常?

【讨论】:

  • 账户余额就是一个很好的例子。查询某人消费的交易历史很繁重,因此跟踪“余额”意味着您只有一个地方可以查看。我认为你的轨道上!
  • 我认为这是反规范化,因为我们存储了过多的数据!
  • 嗯,好点。我觉得你的设计很好。由于需要大量查找,摘要数据对用户帐户很有用。另一个例子是我们跟踪的个人资料访问。我计算了这些,但也将它们存储在子表中。在他们的个人资料页面中,仅获取一个 int 值要快得多。
【解决方案3】:

我认为这不是很有效。当您还需要查找标志的组合时,它可能很有用,例如 post_flags 或 comment_flags 或 photo_flags 并且查询的顺序也很重要。

【讨论】:

  • 在个人资料页面中,我们需要显示一个用户的所有标志的数量。这意味着,我们需要对每个表(posts、cmets、flags)进行计数查询。
猜你喜欢
  • 1970-01-01
  • 2011-12-16
  • 2013-07-17
  • 1970-01-01
  • 2017-02-25
  • 2011-05-18
  • 2018-07-08
  • 1970-01-01
相关资源
最近更新 更多