我需要保留一些关于正在观看的视频的统计数据,其中之一是视频的哪些部分被观看最多。我想出的设计是将视频分成 256 个间隔,并为每个间隔保留浮点数。我以用户连续观看的间隔数的形式接收数据。问题是如何存储它们。我看到有两种解决方案。
每个视频片段的行
让我们有一个这样的数据库表:
CREATE TABLE `video_heatmap` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`video_id` int(11) NOT NULL,
`position` tinyint(3) unsigned NOT NULL,
`views` float NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_lookup` (`video_id`,`position`)
) ENGINE=MyISAM
然后,每当我们必须处理多个视图时,请确保存在相应的数据库行并向views
列添加适当的值。SELECT COUNT(*)
我发现如果首先处理行的存在(给定视频的行以及INSERT IGNORE
是否缺少行)会快得多,然后像这样使用一些更新查询:
UPDATE video_heatmap
SET views = views + ?
WHERE video_id = ? AND position >= ? AND position < ?
然而,这似乎有点臃肿。我想出的另一个解决方案是
每个视频的行,事务中的更新
一张桌子看起来(有点)像这样:
CREATE TABLE video (
id INT NOT NULL AUTO_INCREMENT,
heatmap BINARY (4 * 256) NOT NULL,
...
) ENGINE=InnoDB
然后,每次需要存储视图时,都会在具有一致快照的事务中完成,顺序如下:
- 如果数据库中不存在视频,则创建该视频。
- 检索一行
heatmap
,以二进制形式存储的浮点数组,转换为更易于处理的形式(在 PHP 中)。 - 适当增加数组中的值并将数组转换回来。
- 通过
UPDATE
查询更改行。
到目前为止,优势可以总结如下:
第一种方法
- 将数据存储为浮点数,而不是一些神奇的二进制数组。
- 不需要事务支持,因此不需要 InnoDB,而且我们目前对所有内容都使用 MyISAM,因此不需要混合存储引擎。(仅适用于我的具体情况)
- 不需要交易
WITH CONSISTENT SNAPSHOT
。我不知道这些的性能惩罚是什么。 - 我已经实现了它并且它有效。(仅适用于我的具体情况)
第二种方法
- 使用的存储空间要少得多(第一种方法是存储 256 次视频 ID 并存储视频每个片段的位置,更不用说主键了)。
- 应该更好地扩展,因为 InnoDB 的每行锁定而不是 MyISAM 的表锁定。
- 通常可能工作得更快,因为发出的请求要少得多。
- 更容易在代码中实现(尽管另一个已经实现)。
所以我该怎么做?如果不是我们系统的其余部分始终使用 MyISAM,我会采用第二种方法,但目前我倾向于第一种。但也许有一些理由支持一种或另一种方法?