【问题标题】:SQL Server: Help in table designSQL Server:表设计帮助
【发布时间】:2012-03-18 15:36:26
【问题描述】:

我有一个显示帖子的应用程序,对于每个帖子,用户都可以说出他们是否喜欢该帖子。 对于每个帖子,我应该显示有多少用户喜欢它,有多少用户不喜欢它。 假设我有这些表:

CREATE TABLE [dbo].[Post](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Quotation] [text] NOT NULL,
CONSTRAINT [PK_Post] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,     ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

CREATE TABLE [dbo].[UserPostAction]( --Every action of the user (like or dislike) is     recorded to this table
[PostId] [bigint] NOT NULL,
[UserId] [bigint] NOT NULL,
[ActionValue] [int] NOT NULL, --Like / Dislike
CONSTRAINT [PK_UserPostAction] PRIMARY KEY CLUSTERED 
(
[PostId] ASC,
[UserId] ASC,    
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,      ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  ) ON [PRIMARY]

在性能方面,最好的方法是使用 select 语句返回包含喜欢/不喜欢统计信息的帖子列表:

A) 向 Post 表添加另外 2 列:TotalLike 和 TotalDislike,当向 UserPostAction 插入新记录时,我会更新这些列吗?这样,当从 Post 表中选择帖子时,我将已经计算出统计信息。

B) 添加第三个表:PostStat ([PostId], [TotalLike], [TotalDislike]) 并以批处理的方式更新该表。 select 语句将使用 Post.Id = PostStat.PostId 上的 Inner Join 来检索统计信息。

C) 你能想到的任何其他方式。

希望我有一个包含数百万帖子的数据库,并且很多用户会经常查询 Post 表。 请记住,统计信息会非常频繁地更新,因为很多用户会喜欢或不喜欢很多帖子。这意味着(可能)执行大量更新和表锁定,这会干扰返回要显示的帖子的 select 语句。

欢迎提出任何想法。

【问题讨论】:

  • 如果您一次更新单个帖子,则不应有任何锁定表的风险。还有什么原因您使用 text vs (n)varchar(max) 数据类型?

标签: sql sql-server database-design


【解决方案1】:
I will have a DB with millions of posts

不要认为这是在数据库中维护重复数据的充分理由。

您已经在当前表格中获得了所需的所有信息。这是建立正确索引的问题,您可以轻松计算有多少用户喜欢\不喜欢该帖子。

如果您真的不习惯这种方法,我建议在 UserPostAction 表上使用触发器实现选项 A,以维护您的 2 个新列。

【讨论】:

  • 在每个“Get”上从 UserPostAction 表中计算喜欢/不喜欢不会很好地扩展。
  • 这是一个非常模糊的陈述。基于几个因素,我可以或不能是真的,我们真的不能根据他给我们的信息量得出结论(这只是一个,真的)。这就是为什么我给了 2 个选项
  • Diego - 您建议使用哪些索引?无论索引如何,这种方法对我来说似乎都很昂贵。
  • 您必须对此进行分析。如果您计划按帖子 ID 对结果进行分组并在同一个查询中获取两个结果(如\不喜欢),或者您按 postId 和 actionValue 分组并运行两个查询,情况会有所不同。您必须检查执行计划。但我的观点是,“数百万行”并不是开始考虑数据库上数据重复的那么多数据(可能是这种情况,但我认为你应该在这样做之前探索其他选项)
【解决方案2】:

我遇到了类似的情况,我选择了策略A:

  • 考虑到 Post 和 PostStat 之间存在一对一的关系,将这些信息放在主表上是“正常”选择。
  • 您不必每次查询 Posts 时都在 Post 和 PostStats 表之间进行连接,我认为这比访问包含分散在两者中的相同列的单个表更昂贵。
  • 如果您将使用触发器更新喜欢/不喜欢计数器(我就是这样做的),那么在父表中添加该列将使生活变得更加轻松......事实上,您只需编写一个“更新帖子集 likes = likes + 1 where postId = :new.postId"(oracle sql 语法),并且 postId 上的引用完整性将保证您在那里有一行要更新。

知道写入不会阻塞读取(实际上它们只会读取前一个值,直到事务完成)我怀疑您将列放在主表上时会遇到锁定问题。

【讨论】:

    猜你喜欢
    • 2011-04-21
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 2011-11-06
    • 2016-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多