【问题标题】:Multi Threaded Comments PHP?多线程评论 PHP?
【发布时间】:2011-12-05 20:11:33
【问题描述】:

我有一个我为 cmets 编写的脚本,但它只是单线程的。我希望它是多线程的,但只是用户可以回复评论,而不是用户可以回复评论的评论。所以线程只有两个深。

目前我在我的数据库中存储comment_iduser_id

我能想到的执行多线程 cmets 的唯一方法是在 cmets 表中有一个 parent 字段。但是如果我这样做,那么当我使用 PHP 选择 cmets 时,我将不得不执行另一个 SELECT 命令来为每个注释选择 cmets 子项(如果有)。似乎在数据库上做了很多工作。

必须有更好的方法。对此有什么想法吗?还是教程?

【问题讨论】:

  • 如果不阅读上下文的问题,这个问题绝对没有意义,因为“多线程”和“cmets”通常指的是其他一些。

标签: php mysql sql comments hierarchical-data


【解决方案1】:

有三(四)种替代可能性:

  1. 递归查询,用于根据父 ID 选择所有 cmets。许多数据库产品都支持这一点,语法取决于数据库类型。查看文档了解更多信息(搜索“递归”)。

  2. 如果您将文章 ID 存储在每个(子)评论中,您可以在一个常规选择查询中选择所有具有文章 ID 的 cmets。您可以使用父 id 在页面上正确的父评论下正确显示 cmets:

    SELECT * FROM comments WHERE article_id = :article_id
    
  3. 如果您只需要两级 cmets,您可以使用扩展的 where 来同时包含第一级和第二级 cmets:

    SELECT * FROM comments 
    WHERE parent_id = :article_id
    OR    parent_id IN (SELECT id FROM comments WHERE parent_id = :article_id)
    
  4. 也可以使用 union all 来组合具有相同列的两个查询,但是由于我假设所有数据都来自同一个表,因此可能不需要它(请参阅上面的扩展 where 子句):

    SELECT * FROM comments WHERE parent_id = :article_id
    UNION ALL
    SELECT * FROM comments WHERE parent_id IN 
        (SELECT id FROM comments WHERE parent_id = :article_id)
    

就我个人而言,我会选择选项 2,因为它简单(不需要特殊的 SQL 构造)、高效(1 个查询)和灵活(支持任意级别的 cmets)。

【讨论】:

  • 请你放弃一个真实的 php 代码和结果集的例子......我已经一遍又一遍地阅读你的答案几个小时,我真的不知道如何编码......谢谢
  • @VyrenMedia 我假设您正在尝试实施选项 2。我不会为您提供完整的实施指南,但也许这会有所帮助:blog.tcs.de/creating-trees-from-sql-queries-in-javascript。如果您需要更多帮助,请发布一个新的 SO 问题。
【解决方案2】:

1 次查询就足够了,您只需将数据循环并正确存储到数组中,然后循环数组并显示 cmets。

【讨论】:

  • 这不止一个查询!这就是我解释我无论如何都会这样做的方式,我正在寻找更好的方法
  • 你在谈论使用另一个 SELECT 语句,我给了你一个更好的方法。
  • 不,您的解决方案仍将使用多个 SELECT。感谢您的回答。
  • 如果为每条评论存储文章id,则正好需要一个 SELECT语句,即:SELECT * FROM comment WHERE article_id = :article_id
  • 我的解决方案使用 1 个且不超过 1 个查询。
【解决方案3】:

这是分层或树结构数据的常见用途。我为这个 Stack Overflow 问题写了一个流行的答案:What is the most efficient/elegant way to parse a flat table into a tree?

我还写了一篇介绍树结构数据替代方案的演示文稿:Models for Hierarchical Data with SQL and PHP

另一个未包含在我的演示文稿中的解决方案是 Slashdot 执行线程化 cmets 的方式。他们像您一样使用parent 列,因此每条评论都会引用它回复的评论。但是它们还包含一个root 列,因此每个评论都知道它所属的帖子。给定帖子上很少有超过几百个 cmets,通常您希望从评论线程的顶部开始获取给定帖子的整个 cmets 树:

SELECT * FROM comments WHERE root = 1234;

然后,当您获取 cmets 时,您可以编写 PHP 代码以根据parent 列将它们处理成数组数组(这是@JanL 的答案所暗示的)。我在回答另一个 Stack Overflow 问题Convert flat array to the multi-dimentional 时发布了执行此操作的代码。

【讨论】:

  • 我知道这是一篇旧帖子,但我一直在徘徊,如果您有一个包含数千个 cmets 的帖子,那么您描述的方法将如何工作,您显然不会选择所有行,但是如果您使用 LIMIT 你会失去树结构......有没有办法解决这个问题?......亲切的问候J
  • @jon,您可以使用 LIMIT 但按评论日期排序。所以你会得到最古老的 cmets 线程。然后,如果用户想要扩展线程,他们可以请求它,但默认情况下他们只会看到讨论的子集。如果您想了解更多详细信息,请下载 Slashdot 源代码,看看他们是如何做到的。 slashcode.com
  • 感谢您的回复,但是,如果我对您的理解正确,这只会显示原始评论线程,然后如果他们想扩展评论线程以查看任何回复,您将进行选择那个评论线程,但是我真的很想在第一个查询中显示评论线程的回复,但也能够限制?..这可能使用邻接层次结构吗?..再次感谢 J.
  • @jon,不,如果您使用 MySQL 并且想要支持任意深度的评论回复线程,则在一个查询中的邻接层次结构中是不可能的。这就是为什么人们提出了存储分层数据的替代方法(请参阅我链接到的演示文稿)。其他数据库支持使用通用表表达式进行递归查询,因此可能是可能的。
  • 感谢您一直以来的帮助...我查看了上面链接的您的文章,以及我所理解的内容(我仍在学习!),尽管它们确实是存储 heirachical 的聪明方法数据,邻接方法似乎是存储诸如带有回复的 cmets 之类的最佳方法......因为其他技术在用户发布回复时需要非常复杂的更新。我还仔细查看了 facebook 和 youtube cmets ......
【解决方案4】:

这个查询可能对你有用(我不知道你的结构,所以我猜到了):

SELECT * FROM comments a
LEFT JOIN comments b ON a.comment_id = b.parent_coment_id
LEFT JOIN comments c ON b.comment_id = c.parent_coment_id
WHERE a.comment_id <> b.comment_id
      AND a.comment_id <> c.comment_id
      AND b.comment_id <> c.comment_id;

【讨论】:

  • 这似乎是对的。我假设第二个 LEFT JOIN 和第二个 AND 用于加入 3 级评论?
  • 请注意,这最多适用于 3 个级别的 cmets,并且不会过滤实际文章,我认为这会很有用。
  • 嗯。这附加到最后。我正在寻找一种选择它们的方法,但将它们作为单独的行。
  • 那么你需要一个 UNION 而不是 JOIN(或递归查询)
猜你喜欢
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
相关资源
最近更新 更多