频道 6 万条评论按视频聚合,我用 GROUP BY 踩了空值坑
环境是本机 SQLite 3.45,数据是频道后台导出的评论 CSV,约 6.2 万行,字段有 video_id、author、text、published_at、like_count。想做的事很简单:按视频统计评论条数和平均点赞,挑出互动最集中的 20 条视频。
第一次直接跑聚合,结果对不上后台的总数:
SELECT video_id, COUNT(*), AVG(like_count)
FROM comments
GROUP BY video_id
ORDER BY COUNT(*) DESC
LIMIT 20;
导出来合计只有 5.9 万,差了约 3000 条。先怀疑是导入时丢了行,用 wc -l 数原文件,行数是对的,说明数据进了库,只是聚合时被吞了。
把范围缩小到某个视频单独查,发现它的 video_id 是空字符串,不是 NULL。CSV 里有些行的视频 id 列本来就是空白(后台导出对已删除视频的处理),导入时当成空串写进去。GROUP BY 会把所有空串归成一组,但它不在我预期的视频列表里,肉眼看结果时容易漏掉这一大坨。
处理分两步。导入时统一把空串转成 NULL,并单独建一张排除表:
UPDATE comments SET video_id = NULL WHERE video_id = '';
CREATE TABLE orphan_comments AS
SELECT * FROM comments WHERE video_id IS NULL;
DELETE FROM comments WHERE video_id IS NULL;
然后聚合前先确认分母:
SELECT COUNT(*) FROM comments;
SELECT COUNT(*) FROM orphan_comments;
两个数加起来必须等于原始行数,对不上就停下来查。这样 6.2 万条里 5.9 万条正常、约 3000 条进了 orphan 表,后面做视频维度分析时不再被污染。
为什么不在 GROUP BY 里直接过滤?因为空 video_id 本身是有信息量的:它对应已删除或不可见的视频,评论还在,但视频没了。直接 WHERE 掉会丢掉这批数据,以后想统计“失效视频的评论残留”就没法做了。代价是多一张表、多一次全表 UPDATE,6 万行在本机跑不到一秒,可以接受。
失效的地方有几处。一是 like_count 也有空串,AVG 会把它当 0 参与计算,把均值拉低;我在导入时把空串转成 NULL,AVG 才会跳过。二是 video_id 存在大小写和首尾空格不一致的情况,聚合前得 TRIM 一下,否则同一个视频被拆成两组。三是如果以后数据量上到百万级,UPDATE 全表会锁库,得改成分批处理。我自己第一次就是忘了 TRIM,两个视频的评论被拆开,排名直接错位。
你们在按视频聚合评论时,空 video_id 是单独存一张表,还是直接丢掉?我目前倾向单存,但查询时要多 join 一次,还在权衡。
0 条评论
还没有评论,写下第一条。