You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设计数据库以实现指定时段内Top N热门图片实时统计?

设计思路:实时计算近7天图片Top3浏览量

嘿,这个需求其实挺典型的——既要准确统计近7天的浏览量,又要能实时响应像D那样突然暴涨的排名变化对吧?我来给你拆解几个可行的数据库设计方案,适配不同的业务规模:

1. 核心表结构打底

首先得有两张基础表,先把数据存住:

图片基础信息表 (images)

这张表存图片的固定信息,包括你提到的总浏览量:

CREATE TABLE images (
    image_id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL UNIQUE, -- 比如A、B、C、D
    total_views BIGINT DEFAULT 0, -- 你已有的总浏览量字段
    upload_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    -- 其他元数据比如图片路径、描述之类的按需添加
);

浏览日志表 (image_view_logs)

这是关键!因为我们要统计近7天的浏览量,光靠总浏览量没法拆分时间段,所以必须记录每一次浏览的时间戳:

CREATE TABLE image_view_logs (
    log_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    image_id INT NOT NULL,
    view_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, -- 精确记录浏览发生时间
    FOREIGN KEY (image_id) REFERENCES images(image_id)
);

每次用户浏览图片时,往这张表里插一条记录,同时更新images里的total_views(这个你已经在做了)。

2. 实时获取Top3的实现方案

接下来分场景看怎么高效拿到近7天的Top3:

场景一:小流量业务(每天浏览量几万级)

直接实时计算就行,不用搞复杂的预计算,SQL写起来很直观:

SELECT 
    i.image_id, 
    i.name, 
    COUNT(l.log_id) AS last_7d_views
FROM images i
JOIN image_view_logs l ON i.image_id = l.image_id
WHERE l.view_timestamp >= NOW() - INTERVAL 7 DAY
GROUP BY i.image_id, i.name
ORDER BY last_7d_views DESC
LIMIT 3;

不过要给image_view_logs加个联合索引,不然数据多了会慢:

CREATE INDEX idx_image_time ON image_view_logs(image_id, view_timestamp);

场景二:中高流量业务(每天几十万到百万级)

实时扫描7天的日志会越来越慢,这时候就得用预计算+缓存来提速:

第一步:加一张日统计汇总表 (image_daily_view_stats)

按天统计每个图片的浏览量,避免每次都扫全量日志:

CREATE TABLE image_daily_view_stats (
    stat_id INT PRIMARY KEY AUTO_INCREMENT,
    image_id INT NOT NULL,
    stat_date DATE NOT NULL, -- 统计日期,比如'2024-05-20'
    daily_views BIGINT DEFAULT 0,
    UNIQUE KEY idx_image_date (image_id, stat_date) -- 避免重复统计同一天的数据
);

第二步:实时或定时更新统计数据

  • 定时方式:每天凌晨跑个脚本,把前一天的浏览日志统计到这张表里,比如用SQL:
    INSERT INTO image_daily_view_stats (image_id, stat_date, daily_views)
    SELECT image_id, DATE(view_timestamp) AS stat_date, COUNT(*)
    FROM image_view_logs
    WHERE DATE(view_timestamp) = CURDATE() - INTERVAL 1 DAY
    GROUP BY image_id, stat_date
    ON DUPLICATE KEY UPDATE daily_views = VALUES(daily_views);
    
  • 实时方式:如果要更及时(比如不想等凌晨),可以用消息队列,每收到一条浏览事件,就更新当天的统计数:
    INSERT INTO image_daily_view_stats (image_id, stat_date, daily_views)
    VALUES (?, CURDATE(), 1)
    ON DUPLICATE KEY UPDATE daily_views = daily_views + 1;
    

第三步:查询近7天Top3

现在查询就快多了,只需要汇总最近7天的日统计数据,再加上当天的实时日志(如果用定时更新的话,当天的数据还没进统计表):

SELECT 
    i.image_id,
    i.name,
    -- 过去6天的统计数 + 当天的实时浏览数
    COALESCE(SUM(s.daily_views), 0) + COALESCE(l.today_views, 0) AS last_7d_views
FROM images i
LEFT JOIN image_daily_view_stats s 
    ON i.image_id = s.image_id 
    AND s.stat_date >= CURDATE() - INTERVAL 6 DAY -- 近7天包括今天,所以减6天
LEFT JOIN (
    SELECT image_id, COUNT(*) AS today_views
    FROM image_view_logs
    WHERE DATE(view_timestamp) = CURDATE()
    GROUP BY image_id
) l ON i.image_id = l.image_id
GROUP BY i.image_id, i.name
ORDER BY last_7d_views DESC
LIMIT 3;

第四步:加缓存扛并发

把查询出来的Top3结果存到Redis里,设置个短过期时间(比如1分钟),用户请求先读缓存,缓存失效再查数据库。这样就算10分钟内D的浏览量暴涨,最多1分钟后缓存更新就能看到新排名了。

场景三:超高流量业务(每天千万级以上)

这时候数据库查询可能还是不够快,得用Redis做滑动窗口统计:

  • 每一次浏览事件,执行Redis命令:HINCRBY image:views:hourly:{image_id} {当前小时} 1(比如当前是2024-05-20 14点,键就是image:views:hourly:1:2024052014)
  • 查询近7天Top3时,计算最近7*24=168个小时的哈希值总和,然后排序取前3
  • 定期清理超过7天的小时统计键,避免Redis内存溢出

这种方式完全绕过数据库,响应速度极快,适合超高并发的场景,但需要额外维护Redis的统计逻辑。

3. 关键优化点

  • 给image_view_logs按时间分区(比如按天分区),这样查询近7天数据时,只扫描对应分区,速度翻倍
  • 所有关联查询的字段都要加索引,避免全表扫描
  • 如果不需要精确到每个用户的浏览记录,甚至可以把image_view_logs做成只存每小时的统计数,减少数据量

内容的提问来源于stack exchange,提问作者feerlay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:28:42