计算数据库中某些事件的出现次数

时间:2011-09-02 14:56:12

标签: sql-server

对于我的网站,我想制作的东西有点像Stackoverflow上的标签 - 所以某些字段会有一个自动完成器,自动完成器会显示其他用户选择每个建议值的次数。我想我的数据库结构如下:

Articles
    ArticleID
    Content
    TagId

Tags
    TagId
    TagName
    Occurances

理念是Occurances表示从Articles表中引用每个TagId的次数。

实现此目的的最佳方法是什么?我可以在更新occurances表的每个存储过程的article列中添加/减去,但我可能会错过一个,无论如何,如果用户删除了一个,则存在一些困难。来自某事物的标签(因为它很容易为新添加的标签添加1字段,但更难确定哪个标签正在被替换。)

我对sql-server有很多不了解的地方。是否有更强大的方法来计算这样的出现,数据库系统将处理自己?如果数据每天缓存一次或其他什么就没问题。

4 个答案:

答案 0 :(得分:2)

您可以创建一个索引视图,该视图聚合您需要的所有计数并自动维护:

create view TagCounts 
with schemabinding
as select TagId, count_big(*) as Occurances
from dbo.ArticleTags
group by TagId;
go

create unique clustered index cdxTagCounts on TagCounts (TagId);
go

现在,每当您插入/删除/更新TagCounts.Occurances表时,SQL Server都会自动维护Articles字段。您可以像下面这样查询:

select Occurances from dbo.TagCounts with (noexpand) where TagId = ...;

您可以使用LinqToCache缓存结果,因为这样的查询符合Query Notifications的限制。

使用预聚合索引视图的权衡是可伸缩性:由于任何文章的更新都会更新文章标签的Occurances数量,因此需要使用独占锁来更新此计数。这意味着只有一个事务可以随时使用TagId 。根据您的流量和设计的其他元素,此限制可能是可接受的,也可能是不可接受的。

另一种选择是计数表。前端(您的ASP.Net服务器场)读取此计数,然后更新每个操作的内存中计数,跟踪表中计数的增量。前端定期将它们的增量合并到表中(例如,每5分钟)并刷新内存表。这种方式前端看到了事实的陈旧版本,但是用户看到其动作的即时反馈:由于会话粘性,他的HTTP请求由同一前端处理,因此他立即看到他自己的文章更新触发对其的修改标签计数。用户虽然没有立即看到其他用户的更新,这些更新负载均衡到另一个前端。因为前端的崩溃(或进程回收...)将使得到目前为止保留的增量失去,所以计数表将在时间上偏离事实,并且必须定期更新为数据库中的真实计数。

如果您更准确(所有用户立即看到真实计数),那么您可以根据快速内存中的键值存储执行某些操作,这与我的第一个提案基本相同但吞吐量更高/更低延迟,可能基于memcached + redis。我不熟悉SO架构,但我相信他们可能正在做something similar

答案 1 :(得分:2)

为了能够在文章上附加多个标记,您必须添加另一个将文章表连接到标记表的表。它被称为“多对多”关系。

article
  article_id
  content

article_tag
  article_id
  tag_id

tag
  tag_id
  tagname

这样做,文章1可以附加到代码2,下一行可以是13等等,所以有一篇文章指向很多标签。要计算某个代码,请加入Article_TagTag表格,然后计算Article_TagTag.tagname = 'mysql'所在行的行数。

答案 2 :(得分:1)

您可以使用此查询按标记获取出现次数:

SELECT Tags.TagId, COUNT(Articles.TagId) as Occurances
  FROM Articles
  JOIN Tags ON Articles.TagId
  GROUP BY Tags.TagId

它可以在视图或存储过程中使用,您可以设置网站的缓存,以便根据需要经常重新查询。

答案 3 :(得分:1)

如果您使用的是关系数据库,处理此问题的正确方法是不将事件存储在表本身上,而是动态查询文章表中的出现次数。

如果你不这样做,每次添加/删除行时都会遇到编码更新查询...通常不太好。如果您动态查询,表中不会出现出现列,而是会在您的例如中获取该信息。演示文稿/模型层代码。

使用:

SELECT COUNT(*) FROM ARTICLES WHERE TagId = 'xxx' ;

这一行是迭代代码的一部分。