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

jus*_*der 8 php mysql database optimization

我正在为我的网站设计一个论坛功能数据库.在对SO和谷歌进行一些搜索之后,我想出了以下设计: 用户表

Username : varchar(256)
Password : varchar(256)
Run Code Online (Sandbox Code Playgroud)

线程表

ThreadId  :  int
UserId    :  int, related to Users table
Title     :  varchar(255)
Date      :  timestamp, when a thread was created
Run Code Online (Sandbox Code Playgroud)

帖子表

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
Run Code Online (Sandbox Code Playgroud)

即使这符合我的目的,我也忍不住认为这不是很有效,特别是为了选择特定线程的所有帖子,必须遍历整个表格.

从我的头脑中,我可以想到一个设计,其中Users表Threads表保持不变,但我没有为Posts表创建一个,而是为每个具有相同名称的用户创建一个Posts表.检索属于线程的所有帖子的方式效率要高得多,因为我需要的只是启动线程的人的用户ID.通过这些信息,我搜索具有相同名称的表来检索所有帖子特定的线程.但是让我创建的表的数量直接取决于注册用户的数量是一个好主意吗?我还想知道的是,这些设计中哪一个会更好地扩展,更容易管理?是否有更好的数据库设计满足我的要求?

Rob*_*lie 10

你的设计看起来基本正确.

这是一个经典的"规范化"数据结构 - 正是为关系数据库构建的那种形状.如果您不了解正常表单,但想出了这种结构,那么您显然可以自然地了解关系数据库的工作原理.

http://en.wikipedia.org/wiki/Database_normalization#Normal_forms

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

SELECT * FROM posts WHERE ThreadId = ? ORDER BY Date
Run Code Online (Sandbox Code Playgroud)

您担心数据库必须遍历整个表是公平合理的,尽管您可以避免这种情况 - 这是一个典型的关系数据库问题,这些问题在30多年前首次作为商业产品出现时就已经解决了.

您可以支持您正在运行的SQL的帖子上创建INDEX.在这种情况下,有些东西:

CREATE INDEX postThreadsIndex ON posts ( ThreadId, Date )
Run Code Online (Sandbox Code Playgroud)

此索引允许您的数据库引擎快速查找您正在选择的记录,而无需阅读整个表.如果你想知道如何,请阅读b-tree索引.

http://en.wikipedia.org/wiki/B-tree

正如我之前在答案中所说的那样,这正是为关系数据库构建的那种东西,而且您的设计是可靠且适当的.

不要考虑任何替代方案 - 你第一次就做对了!

但是,为了完成起见 - 让我们看看你建议的替代方案.

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

  • 用户"UserA"创建一个帖子 - 他的初始帖子存储在posts_UserA中
  • 用户"UserB"响应帖子 - 他的帖子在posts_UserB中存储
  • 用户"UserC"响应帖子 - 她的帖子在posts_UserC中存储

要检索完整的线程,您现在需要查看posts_UserA,posts_UserB和posts_UserC.

如果这是唯一的三个用户,那么你就需要通过这些threee表中的所有数据看,以便找到所有的职位,而这将是相等的记录数已经在表的帖子在你的原创设计.

你一无所获.

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

你仍然一无所获.

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

可以通过Thread拆分Post表 - 这意味着表中的所有帖子都基于它们所在的线程.这可能非常适合在单个线程上选择帖子,但这对于: - 选择给定用户发布的所有帖子来说非常糟糕. - 无论线程如何,找到最新的帖子. - 查找特定日期的所有帖子. - 任何其他不涉及特定线程的内容.

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

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

如果由于数据量太大而导致SQL性能太慢,那么您可以查看表分区,它以不可见的方式执行您所描述的内容.但说实话,除非您的网站非常受欢迎,否则您不太可能需要它 - 如果是这样的话,那么您可能会有现金投入关系数据库课程的基础知识,无论如何......

  • 我已经大幅更新了我的答案 - 我希望这涵盖了您的大部分问题。 (2认同)