我正在使用简单规范化数据库的网站上工作。
有一个名为Pages的表和一个名为Views的表。每次查看页面时,该视图的唯一记录都会记录在视图表中。
在网站上显示页面时,我使用一个简单的MySQL COUNT()来总计显示的视图数量。
数据库设计看起来很好,除了这个问题:我对如何在数千个页面中查找前10个最常查看的页面感到茫然。
我应该通过添加Pages.views列来对页面表进行非规范化,以保存每个页面的总观看次数吗?或者是否有一种有效的方法来查询前10个查看次数最多的页面?
答案 0 :(得分:8)
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;
我无法测试这一点,但这些都是这样的。我不会存储该值,除非我必须由于性能限制(我刚刚学会了术语“过早优化”,如果你这样做,它似乎适用。)
答案 1 :(得分:3)
这取决于您尝试维护的信息级别。如果你想记录谁查看的时间?然后单独的表是好的。否则,View的列就是要走的路。此外,如果您保留一个单独的列,您将发现该表将被更频繁地锁定,因为每个页面视图将尝试更新其对应行的列。
Select pageid, Count(*) as countCol from Views
group by pageid order by countCol DESC
LIMIT 10 OFFSET 0;
答案 2 :(得分:1)
我可能会在Pages表中包含views列。
对我而言,这似乎是一种完全合理的正常化。特别是因为我无法想象你删除了视图所以你不会指望计数能够摆脱困境。在这种情况下,参照完整性似乎不是至关重要的。
答案 3 :(得分:1)
数据库规范化是关于存储数据的最有效/最少冗余的方式。这对于事务处理很有用,但通常直接与有效地再次获取数据的需求相冲突。通常通过使用更易于访问的预处理数据的派生表(索引,物化视图,汇总表...)来解决该问题。这里(稍微过时)的流行语是Data Warehousing。
我认为您希望将Pages表格标准化,但是要有一个额外的表格。根据这些计数的最新需求,您可以在更新原始表时更新表,也可以让后台作业定期重新计算总计。
只有在遇到性能问题时才会这样做,除非你有大量的记录或大量的并发访问,否则你不会这样做。保持代码的灵活性,以便能够在拥有表格和没有表格之间切换。
答案 4 :(得分:0)
在这种情况下,非规范化肯定会起作用。您的损失是额外列耗尽的额外存储空间。
或者,您可以设置预定作业,以便在您的流量较低时,每隔一段时间填充此信息。
在这种情况下,除非您手动运行此查询,否则您将无法立即知道您的页数。
非正规化绝对可以用来提高性能。
- 克里斯
答案 5 :(得分:0)
虽然这是一个老问题,但我想补充一下我的答案,因为我发现接受的答案被误导了。
为单个选定行设置 COUNT 是一回事;对所有列的 COUNT 进行排序是另一回事。
即使您只有 1000 行,每行都通过一些连接进行计数,您也可以轻松地读取数万行,甚至数百万行。
如果你只是偶尔调用这个也可以,但否则成本会很高。
你可以做的是添加一个触发器:
CREATE TRIGGER ins AFTER INSERT ON table1 FOR EACH ROW
UPDATE table2
SET count = count + 1
WHERE CONDITION