使用php和mysql为简单论坛设计高效的数据库

使用php和mysql为简单论坛设计高效的数据库,php,mysql,database,optimization,Php,Mysql,Database,Optimization,我正在为我的网站设计一个论坛功能数据库。在搜索了SO和google之后,我提出了以下设计: 用户表 Username : varchar(256) Password : varchar(256) ThreadId : int UserId : int, related to Users table Title : varchar(255) Date : timestamp, when a thread was created PostId : int

我正在为我的网站设计一个论坛功能数据库。在搜索了SO和google之后,我提出了以下设计: 用户表

Username : varchar(256)
Password : varchar(256)
ThreadId  :  int
UserId    :  int, related to Users table
Title     :  varchar(255)
Date      :  timestamp, when a thread was created
PostId   :   int
ThreadId :   int, related to Threads table
UserId   :   int, related to Users table
Date     :   timestamp, when post was made
Title    :   varchar(255) - post title (optional)
Body     :   text - the actual body of a post
线程表

Username : varchar(256)
Password : varchar(256)
ThreadId  :  int
UserId    :  int, related to Users table
Title     :  varchar(255)
Date      :  timestamp, when a thread was created
PostId   :   int
ThreadId :   int, related to Threads table
UserId   :   int, related to Users table
Date     :   timestamp, when post was made
Title    :   varchar(255) - post title (optional)
Body     :   text - the actual body of a post
帖子表

Username : varchar(256)
Password : varchar(256)
ThreadId  :  int
UserId    :  int, related to Users table
Title     :  varchar(255)
Date      :  timestamp, when a thread was created
PostId   :   int
ThreadId :   int, related to Threads table
UserId   :   int, related to Users table
Date     :   timestamp, when post was made
Title    :   varchar(255) - post title (optional)
Body     :   text - the actual body of a post
尽管这符合我的目的,但我还是忍不住认为这不是很有效,特别是对于选择某个特定线程的所有帖子,需要遍历整个表


从我的脑海中,我可以想到一种设计,其中用户表线程表保持原样,而不是为帖子表设置一个表,我为每个与用户同名的用户创建了一个Posts表,因为我只需要启动线程的人的用户ID。根据这些信息,我搜索同名表以检索特定线程的所有帖子。但是,让我创建的表的数量直接取决于注册用户的数量是不是一个好主意?我还想知道的是,这些设计中,哪一种更易于管理,规模更大?有更好的数据库设计满足我的要求吗?

您的设计看起来基本正确

这是一种典型的“标准化”数据结构,正是构建关系数据库的目的。如果您不知道标准形式,但提出了这种结构,那么您显然对关系数据库的工作方式有着自然的理解

为了让PHP避免遍历整个表,您应该确保发出一条SQL语句,该语句只选择要查找的记录。例如

SELECT * FROM posts WHERE ThreadId = ? ORDER BY Date
您对数据库必须遍历整个表的担心是合理的,尽管您可以避免这种情况——这是一个经典的关系数据库问题,在30多年前作为商业产品首次出现时就已经解决了

您可以在帖子上创建一个支持您正在运行的SQL的索引。在这种情况下,应遵循以下原则:

CREATE INDEX postThreadsIndex ON posts ( ThreadId, Date )
此索引允许数据库引擎快速查找所选记录,而无需读取整个表。如果你想知道怎么做,请仔细阅读b树索引

正如我在前面的回答中所说的,这正是构建关系数据库的目的,您的设计是可靠和适当的

不要考虑任何其他的选择——你第一次做对了!<强>

但是,为了完整起见,让我们看看您建议的替代方案

您建议按用户拆分Post表-这意味着:

  • 用户“UserA”创建一个线程-他的初始帖子存储在posts\u UserA中
  • 用户“UserB”响应帖子-他的帖子被存储在posts\u UserB中
  • 用户“UserC”响应帖子-她的帖子被存储在posts\u UserC中
为了检索完整的线程,您现在需要查看posts\u UserA、posts\u UserB和posts\u UserC

如果这是仅有的三个用户,那么您需要查看这三个表中的所有数据,以便找到所有的POST,这将等于原始设计中表POST中的记录数

你一无所获

如果您有1000个其他用户,您还必须查看其他1000个表,以发现他们没有任何记录

你还是一无所获

您可以添加另一个表来存储哪些用户对哪些帖子发表了评论,从而可以查看哪些表,但现在解决方案开始变得复杂起来

您可以按线程分割Post表,这意味着表中的所有Post都是基于制作它们的线程的。这对于在单个线程上选择帖子可能是非常好的,但对于以下情况则非常糟糕: -选择给定用户的所有帖子。 -查找最新的帖子而不考虑线程。 -查找在特定日期发布的所有帖子。 -不涉及特定线程的任何其他内容

基本上,您建议的替代方法对于非常特定的查询可能更有效,但对于任何其他查询,它几乎总是极其复杂的

原始设计对于所有查询都更简单,并且可以通过添加索引使其运行良好。


如果您的SQL性能由于数据量太大而变得太慢,那么您可以看看表分区,它以一种不可见的方式实现了您所描述的功能。但老实说,除非你的网站非常受欢迎,否则你不太可能需要它——如果是这样的话,那么你可能会有足够的资金来投资关系数据库基础课程……

看看:尽管显然使用PDO或mysqli代替,即使我为帖子创建了索引,threadid由于php服务器必须遍历整个表以检索特定threadid的记录,因此它仍然是低效的(内部),因此我提出了第二种设计。您对第二种数据库设计(而不是第一种)有何看法?不,PHP不需要遍历整个表,因为您将使用SQL选择所需的记录。例如,从threadId=?抱歉,sql必须遍历整个表才能找到具有特定threadId的所有条目的帖子中选择*。您认为以下内容在内部是如何工作的?通过遍历整个表来完成吗?即使从threadId=?,的帖子中选择*,会做我想做的,但会比第二个数据库设计慢,对吗?不,不会,如果你使用索引t