如何在此发布系统中超过 64 个通道(位)


How to exceed 64 channels (bits) in this publishing system

编辑:

在下面的问题中,我简化了我的问题,因此很容易解释。 我现在可以看到,根据前几条评论,我把它简化了。 因此,当您通读时,请记住这个新事实:系统中的发布者数量几乎与用户数量一样多,每个发布者都可以有自己的兴趣组列表(最好是数千个)。 简而言之,请把它视为速度很重要,而简单的列表不会削减它......

结束编辑。

我正在设计一个系统,用于使用MySQL和PHP向用户发布帖子(博客风格的文章)。 帖子发布到"兴趣小组",用户注册以阅读特定的兴趣小组。 当用户请求他们的新闻提要时,我需要能够尽快组合并返回文章列表。

为了提高速度,我使用按位运算符从数据库中选择帖子。 每个兴趣组对应于整数中的一个位。 每个帖子都有一个"发布掩码",这是一个整数,用于存储发布到的组。 每个用户都作为"读取掩码",这是一个整数,用于存储用户感兴趣的组。

例如,兴趣小组可能如下所示:

  • 位 0(十进制 1):钓鱼
  • 位 1(十进制 2):丛林漫步
  • 位 2(十进制 4):跳伞

在这种情况下,帖子的发布掩码可能是"3"(钓鱼和丛林漫步)。 读取掩码为"5"(钓鱼和跳伞)的用户可以访问该文章,但读取掩码为"4"的用户无法访问。 帖子的选择发生在 SQL 查询中。 该查询仅使用 WHERE 子句,该子句返回用户读取掩码和每个帖子的发布掩码之间的按位 AND 的布尔结果。

所以......这真的很有效,除了一个明显的问题:我仅限于64个兴趣小组。 对于我的生活,我想不出一种优雅的方式来绕过它。

我可以添加第二对掩码并将 WHERE 子句基于 ((PubMask1 AND ReadMask1) || (PubMask2 AND ReadMask2))但是这种"线性"方法只给了我 128 个组。 如果我想要,比如说,3000怎么办?

我查看了 PHP GMP 库,但这无济于事 - 我不想从数据库中提取所有内容以在 PHP 中过滤它 - 而且我找不到任何 GMP 等效的 MySQL 插件。 (除此之外,我不确定多个精度库的速度会是什么样子)。

我是否还缺少其他可能性? 例如,有没有办法存储一长串零和一并对其执行二进制算术?

一种可能的解决方案是使用上述掩码对(PubMask1,PubMask2,ReadMask1,ReadMask2),并让每个帖子记录具有多个发布记录(并且每个用户有多个读取掩码记录)。 在这种情况下,我最多可以有 64 x 64 个兴趣组,但如果可以的话,我真的不想在这个高性能方案中引入一对多关系。

你在这里建议的是深入一个很深的兔子洞,实际上不会产生任何性能改进。事实上,它可能会产生相反的效果,使您的架构不仅令人讨厌使用,而且由于非标准标记方法而导致的性能问题而瘫痪。在像MySQL这样的RDBMS中,你越是违背原则,你就越会受到性能问题的惩罚。

书本计算的方法是使用一个简单的关联表,将帖子链接到组:

CREATE TABLE post_group_links(
  id INT AUTO_INCREMENT PRIMARY KEY,
  post_id INT NOT NULL,
  group_id INT NOT NULL,
  UNIQUE KEY `index_pgl_post_group` (`post_id`,`group_id`)
);

UNIQUE索引约束意味着帖子和组之间只能有一个关联。像MySQL这样的数据库使得获取一个组的所有文章变得简单而快速:

SELECT posts.* FROM posts
  LEFT JOIN post_group_links ON posts.id=post_id
  WHERE post_group_links.group_id=?

即使是大型数据库,这也应该以毫秒为单位运行,因为索引会处理它。如果要对这些帖子进行排序,可能需要向联接表添加某种排序数据,但这很容易添加并合并到索引中。

如果您想使用独家AND在多个组中查找帖子,也可以使用大致如下内容,尽管速度较慢:

SELECT posts.* FROM posts
  LEFT JOIN post_group_links ON posts.id=post_id
  WHERE post_group_links.group_id IN (?,?,?)
  GROUP BY posts.id
  HAVING COUNT(post_group_links.id)=3

有很多方法可以编写它,包括使用子查询(如果这样可以更容易遵循)。

这将轻松扩展到数千个组中的数百万个帖子。一个现代的SSD支持的MySQL服务器甚至不会在每分钟运行数千次这样的查询时费力,并且可以使用更高级的技术(如分区或水平分片)进行调整以运行得更快。

您提出的解决方案涉及少量 64 位列,直接违反了重要的零、一或无穷大规则。像 PubMask1PubMask2 这样的列几乎总是具有基本设计问题的模式的明确标志。