2

我需要保留一些关于正在观看的视频的统计数据,其中之一是视频的哪些部分被观看最多。我想出的设计是将视频分成 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

然后,每次需要存储视图时,都会在具有一致快照的事务中完成,顺序如下:

  1. 如果数据库中不存在视频,则创建该视频。
  2. 检索一行heatmap,以二进制形式存储的浮点数组,转换为更易于处理的形式(在 PHP 中)。
  3. 适当增加数组中的值并将数组转换回来。
  4. 通过UPDATE查询更改行。

到目前为止,优势可以总结如下:

第一种方法

  • 将数据存储为浮点数,而不是一些神奇的二进制数组。
  • 不需要事务支持,因此不需要 InnoDB,而且我们目前对所有内容都使用 MyISAM,因此不需要混合存储引擎。(仅适用于我的具体情况)
  • 不需要交易WITH CONSISTENT SNAPSHOT。我不知道这些的性能惩罚是什么。
  • 我已经实现了它并且它有效。(仅适用于我的具体情况)

第二种方法

  • 使用的存储空间要少得多(第一种方法是存储 256 次视频 ID 并存储视频每个片段的位置,更不用说主键了)。
  • 应该更好地扩展,因为 InnoDB 的每行锁定而不是 MyISAM 的表锁定。
  • 通常可能工作得更快,因为发出的请求要少得多。
  • 更容易在代码中实现(尽管另一个已经实现)

所以我该怎么做?如果不是我们系统的其余部分始终使用 MyISAM,我会采用第二种方法,但目前我倾向于第一种。但也许有一些理由支持一种或另一种方法?

4

1 回答 1

1

第二种方法乍一看很诱人,但它使诸如“视频y的片段x有多少观看次数”之类的查询无法在. 不过,不确定这是否是您现实生活中的担忧。此外,每次只需要一个段的数据时,您都必须来回解析整个数组。video.heatmap

但首先,您的第二个解决方案是骇人听闻的(但仍然很有趣)。在您遇到实际性能问题之前,我不建议您对数据库进行非规范化。

此外,请尝试在插入 a后立即填充video_headmap表(触发器可以提供帮助)。wiews = 0video

如果空间确实是一个问题,请删除您的代理键video_headmap.id(video_id, position)改为主键(然后摆脱多余的UNIQUE约束)。但这不应该进入等式。每个视频 256 x 12 字节(粗略的行长和 3 个数字列,可以为索引添加一些)只是每个视频额外的 3kb!

最后,没有什么能阻止您将当前表切换到 InnoDB 并利用其行级锁定功能。

请注意,我不明白为什么views不能成为UNSIGNED INT. 我建议更改此类型。

于 2013-06-24T16:18:49.483 回答