题
我正在开发一个带有简单标准化数据库的网站。
有一个名为“页面”的表和一个名为“视图”的表。每次查看页面时,该视图的唯一记录都会记录在视图表中。
在网站上显示页面时,我使用简单的 MySQL COUNT() 来总计显示的视图数。
数据库设计看起来不错,除了这个问题:我不知道如何检索数千个浏览次数最多的页面中的前 10 个。
我是否应该通过添加 Pages.views 列来保存每个页面的总浏览次数来对 Pages 表进行非规范化?或者有没有一种有效的方法来查询浏览次数最多的前 10 个页面?
解决方案
SELECT p.pageid, count(*) as viewcount FROM
pages p
inner join views v on p.pageid = v.pageid
group by p.pageid
order by count(*) desc
LIMIT 10 OFFSET 0;
我不能测试这个,但是这些方面的东西。我不会存储该值,除非我必须由于性能限制(我刚学会了术语“过早优化”,如果你这样做,它似乎适用。)
其他提示
这取决于您试图维护的信息级别。如果你想记录谁浏览过什么时间?那么单独的表就可以了。否则,视图列就是正确的选择。另外,如果保留单独的列,您会发现该表将更频繁地被锁定,因为每个页面视图都会尝试更新其相应行的列。
Select pageid, Count(*) as countCol from Views
group by pageid order by countCol DESC
LIMIT 10 OFFSET 0;
我可能会在Pages表中包含views列。
对我而言,这似乎是一种完全合理的正常化。特别是因为我无法想象你删除了视图所以你不会指望计数能够摆脱困境。在这种情况下,参照完整性似乎不是至关重要的。
数据库规范化是关于存储数据的最有效/最少冗余的方式。这对于事务处理很有用,但通常直接与有效地再次获取数据的需求相冲突。通常通过使用更易于访问的预处理数据的派生表(索引,物化视图,汇总表...)来解决该问题。这里(稍微过时)的流行语是Data Warehousing。
我认为您希望将Pages表格标准化,但是要有一个额外的表格。根据这些计数的最新需求,您可以在更新原始表时更新表,也可以让后台作业定期重新计算总计。
只有在遇到性能问题时才会这样做,除非你有大量的记录或大量的并发访问,否则你不会这样做。保持代码的灵活性,以便能够在拥有表格和没有表格之间切换。
在这种情况下,非规范化肯定会起作用。您的损失是额外列耗尽的额外存储空间。
或者,您可以设置预定作业,以便在您的流量较低时,每隔一段时间填充此信息。
在这种情况下,除非您手动运行此查询,否则您将无法立即知道您的页数。
非正规化绝对可以用来提高性能。
- 克里斯