【发布时间】:2012-03-01 21:51:02
【问题描述】:
我正在我的应用中构建一个嵌套的评论回复系统。
目前一切都按预期工作,但是我发现自己必须使用多个 MySQL 查询才能检索所需的数据。更糟糕的是,“回复”的查询是在 foreach 循环中。这意味着尽管它目前的表现令人钦佩,但它远非最佳,并且会随着数据集的增长而导致问题。
因此,我希望在深入开发之前解决这个问题。
由于应用程序的表格与网站的 wordpress 博客共享相同,因此我使用 wordpress 速记进行查询。
当前页面生成方式如下:
查询一个 cmets 表并检索与一个 projectid 相关的所有结果:-
$commentquery = "select projects_comments.*, users.user_url, users.display_name
from ".$wpdb->prefix."projects_comments projects_comments
left join ".$wpdb->prefix."users users on users.ID=projects_comments.userid
where projectid = '$projectid'
order by projects_comments.commentid desc
";
$comments = $wpdb->get_results($commentquery);
然后我执行如下的 foreach 循环:-
if($comments) {
foreach ( $comments as $c )
{
$replyquery = "select project_replies.*, users.user_url, users.display_name
from ".$wpdb->prefix."project_replies project_replies
left join ".$wpdb->prefix."users users on users.ID=project_replies.uid
where project_replies.cid = '$c->commentid'
order by project_replies.id desc
limit 2
";
$replies = $wpdb->get_results($replyquery);
asort($replies);
$countquery = "select count(*)
from ".$wpdb->prefix."project_replies project_replies
where project_replies.cid='".$c->commentid."'
";
$replycount = $wpdb->get_var($countquery);
//generate html here
}
}
在这个循环中还有两个查询。第一个获取每个评论的回复,但将结果限制为 2(我希望这样做是为了有一个“查看所有回复”按钮,然后如果用户需要它们,则查询数据库以获取其余部分),第二个查询计数回复总数。
然后,还使用上述循环中的第二个嵌套 foreach 为循环中的每个回复生成 html(此处表示在此处生成 html 代码),如下所示:-
if ($replies){
foreach ( $replies as $r ){
// generate each reply
}
}
通过以下方式从这些数组中提取所有数据:
$c->userid, $c->body etc... For the comments
$r->userid, $r->body etc... For the replies.
如果可能的话,我希望保持这种格式。
因此,正如问题开头所述,这一切都很完美,但是我知道通过嵌套回复和计数查询,我执行的查询比必要的多得多。 100 cmets 将生成 100 个回复查询和 100 个计数回复查询等。
感谢本网站上的一些乐于助人的人,我考虑使用联接来一次性获取所有原始数据,以供 cmets 和回复使用。就这样……
$commentquery2 = "SELECT c.commentid, c.userid, c.body as cbody, c.projectid, c.posttime, cu.user_url AS cu_url, cu.display_name AS cu_name,
r.*, ru.user_url AS ru_url, ru.display_name AS ru_name
FROM ".$wpdb->prefix."projects_comments AS c
LEFT JOIN ".$wpdb->prefix."users AS cu ON cu.ID = c.userid
LEFT JOIN ".$wpdb->prefix."project_replies AS r ON r.cid = c.commentid
LEFT JOIN ".$wpdb->prefix."users AS ru ON ru.ID = r.uid
WHERE c.projectid = $projectid
ORDER BY c.commentid DESC, r.id DESC";
虽然这确实有效(并且足以让我将该问题标记为已回答),但在将其付诸实践时,我遇到了一些困难。
首先,这会将所有数据作为单独的行检索,这意味着如果我有 5 个 cmets,每个 cmets 有 3 个回复,我实际上会返回 15 行,而不是一个嵌套数据对象,回复嵌套在每个评论行中。
为了解决这个问题,我尝试了一些数组操作,如下所示:
$old_id=NULL;
$comments=array();
foreach($getcomments as $c){
if($c->commentid !== $old_id){
$comments[$old_id] = $c;
$old_id = $c->commentid;
}
$comments[$old_id]['replies'][] = $c;
}
这样做会根据需要给我一个嵌套的数据对象。但是,它不包括回复计数查询,也没有按预期将每组回复限制为 2 个,而是检索所有回复。
最后在 foreach 循环中使用我当前的 html 生成代码:
foreach($comments){
//generate comment html
foreach($replies) {
//generate replies html
}
}
我似乎无法让它与嵌套数据对象一起正常工作。访问正确的深度回复似乎让我感到困惑。
总而言之,我希望能够删除循环查询,将它们组合成一个更大且更高效的查询,或者最坏的情况是一个数据查询和一个单独的计数查询,然后创建一个整齐嵌套的数据对象, cmets 作为行和嵌套在标题“回复”下的任何回复
然后我需要能够在我的 php 代码中正确地遍历这些以生成所需的 html。
对于这个问题的冗长,我深表歉意,并意识到这可能会让你们中的许多人无法回答,但我已经为此奋斗了 19 个小时,真的需要帮助。
非常感谢任何提供任何建议的人。
【问题讨论】:
-
可能只是将您的表格添加到示例数据中,而您期望获得的结果表格应该更有用。
-
很可能是莫斯蒂,点了。如果我在 10 分钟开始前还有 2 小时的车程不是那么着急,我会按照你的建议编辑问题。
-
这已经被报道过几次,包括这篇文章:stackoverflow.com/questions/317322/…
-
感谢工匠,这很有趣,我没有考虑过......但是,您的链接中描述的嵌套系统是否适合简单的评论/回复系统?既然它永远只有一层深,这不是大材小用吗?或者它仍然会比任何其他方法提供更好的读取性能吗?干杯