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

Php 如何在此发布系统中超过64个通道(位),php,mysql,performance,bit-manipulation,Php,Mysql,Performance,Bit Manipulation,编辑: 在下面的问题中,我简化了我的问题,因此很容易解释。根据前面的几条评论,我现在可以看出,我把它过于简化了。因此,当您通读时,请记住一个新事实:系统中的发布者几乎可以和用户数量一样多,每个发布者可以有自己的兴趣组列表(最好是数千个)。简言之,请把它作为一个给定的速度是重要的,而简单的列表只是不会削减它 结束编辑 我正在设计一个系统,使用MySQL和PHP向用户发布文章(博客风格的文章)。帖子发布到“兴趣组”,用户注册阅读特定的兴趣组。当用户请求他们的新闻提要时,我需要能够尽快收集并返回文章列

编辑:

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

结束编辑

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


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

举例来说,利益集团可能如下:

  • 位0(十进制1):钓鱼
  • 第1位(十进制2):灌木行走
  • 第2位(十进制4):跳伞
在这种情况下,post的发布掩码可能是,比如“3”(钓鱼和丛林行走)。阅读掩码为“5”(钓鱼和跳伞)的用户可以访问该文章,但阅读掩码为“4”的用户不能访问。帖子的选择发生在SQL查询中。查询只使用WHERE子句,该子句返回用户的读取掩码和每篇文章的发布掩码之间按位AND的布尔结果

所以。。。除了一个明显的问题:我被限制为64个兴趣组之外,这个方法非常有效。就我个人而言,我想不出一个优雅的方式来解决这个问题

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

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

还有什么我错过的可能性吗?例如,有没有一种方法可以存储一长串的0和1,并对它们执行二进制运算


一种可能的解决方案是使用如上所述的掩码对(PubMask1、PubMask2、ReadMask1、ReadMask2),并让每个post记录具有多个发布记录(每个用户具有多个读取掩码记录)。在这种情况下,我最多可以有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
索引约束意味着您可以在post和组之间有一个且只有一个关联。MySQL这样的数据库使得为一个组获取所有文章变得简单而快速:

SELECT posts.* FROM posts
  LEFT JOIN post_group_links ON posts.id=post_id
  WHERE post_group_links.group_id=?
即使对于大型数据库,它也应该在毫秒内运行,因为索引将处理它。如果要对这些帖子进行排序,可能需要向联接表中添加某种排序数据,但添加并合并到索引中并不重要

如果您想使用独占的
在多个组中查找帖子,也可以使用类似以下内容,尽管速度较慢:

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位列的解决方案直接违反了重要的规则。像
PubMask1
PubMask2
这样的列几乎总是架构存在基本设计问题的可靠标志。

所以……不要使用位掩码。为了提高速度,使用列-这是一种微观优化。正如您已经发现的,与有限的灵活性相比,性能方面的成本微不足道。答案很简单——不要这样做:使用列表。SQL中正确索引的联接列(或表)可以很快做到这一点(实际速度可能相同)。“为了提高速度,我使用位运算符从数据库中选择帖子。”这些语句相互矛盾。MySQL中的位掩码速度非常慢,因为它们无法被索引。