对于我的网站,我想制作的东西有点像Stackoverflow上的标签 - 所以某些字段会有一个自动完成器,自动完成器会显示其他用户选择每个建议值的次数。我想我的数据库结构如下:
Articles
ArticleID
Content
TagId
Tags
TagId
TagName
Occurances
理念是Occurances表示从Articles
表中引用每个TagId的次数。
实现此目的的最佳方法是什么?我可以在更新occurances
表的每个存储过程的article
列中添加/减去,但我可能会错过一个,无论如何,如果用户删除了一个,则存在一些困难。来自某事物的标签(因为它很容易为新添加的标签添加1字段,但更难确定哪个标签正在被替换。)
我对sql-server有很多不了解的地方。是否有更强大的方法来计算这样的出现,数据库系统将处理自己?如果数据每天缓存一次或其他什么就没问题。
答案 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
,下一行可以是1
和3
等等,所以有一篇文章指向很多标签。要计算某个代码,请加入Article_Tag
和Tag
表格,然后计算Article_Tag
中Tag.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' ;
这一行是迭代代码的一部分。