Php 如何以最少的查询次数获取帖子列表和相关标签

Php 如何以最少的查询次数获取帖子列表和相关标签,php,mysql,sql,angularjs,Php,Mysql,Sql,Angularjs,我的表格结构如下: 标记(更多类别):id、标记名称、描述、slug 帖子:id、标题、url POSTSTAGS:id、idPost、idTag 用户:id、用户名、userSlug 投票:id、idPost、idUser 每个帖子最多可以有五个标签,每个用户只能投票一次。目前,由于标记尚未实现,我使用以下查询检索分页结果集: SELECT p.*, u.username, u.userSlug, u.id as userId, exists (select 1 from votes v w

我的表格结构如下:

标记(更多类别):id、标记名称、描述、slug

帖子:id、标题、url

POSTSTAGS:id、idPost、idTag

用户:id、用户名、userSlug

投票:id、idPost、idUser

每个帖子最多可以有五个标签,每个用户只能投票一次。目前,由于标记尚未实现,我使用以下查询检索分页结果集:

SELECT p.*, u.username, u.userSlug, u.id as userId, 
exists (select 1 from votes v where v.idUser=$id AND p.userId=v.idUser AND p.url = v.url) as voted 
FROM posts p 
JOIN users u ON u.id=p.userId
ORDER BY p.created DESC
LIMIT 10 OFFSET :offset
查询通过PDO运行,并以JSON格式返回到angularjs
ng repeat
$id
是登录用户的id。我在
exists
子查询中使用它来灰显角度视图中的投票按钮(服务器端也有一个检查)。如果有人在视图中单击用户名,他将被带到一个详细页面,其中显示所有用户的帖子(
userSlug
to the rescue)

下一步是将标签包括在结果列表中,这里我结结巴巴地说。列表中的每个帖子必须包含所有关联的标签(标记名、描述、slug),每个标签必须带您进入一个详细信息页面,其中显示了该特定标签的所有关联帖子

我想到的第一个解决方案是,在运行前面提到的查询之后,强行通过此操作:

foreach ($postsResult as &$post) {
    $sql ="SELECT t.* FROM tags t JOIN poststags pt ON t.id=pt.idTag WHERE pt.idPost=$post->id";
    $stmt=$db->prepare($sql);
    $stmt->execute();
    $tagsResult=$stmt->fetchAll(PDO::FETCH_OBJ);
    $post->tags = $tagsResult;
}
$response->write(json_encode($postsResult));
好了,轻松点!大量的查询将给服务器带来巨大的压力。我们不想这样做

第二种解决方案是触发另一个查询,该查询获取与postsResult相关联的所有标记,然后在每个post中插入相应的标记,让PHP执行脏工作

$sql = "
    SELECT t.*, 
           pt.idPost 
      FROM tags t JOIN poststags pt ON t.id=pt.idTag 
     WHERE pt.idPost IN (array of post ids)
";
$stmt=$db->prepare($sql);
$stmt->execute();
$tagsResult = $stmt->fetchAll(PDO::FETCH_OBJ);

foreach ($postsResult as &$post) {
    $arr = array();

    foreach ($tagsResult as $tag) {
        if ($post->id==$tag->idPost) {
            $arr[]=$tag;
        }
    }

    $post->tags = $arr;
}
$response->write(json_encode($postsResult));
有没有更好或更快的方法

有没有更好或更快的方法

如果您通过
postId
索引
$tagsResult
,您可以使用
FETCH\u GROUP
执行此操作,那么您可以删除内部嵌套循环并在固定时间内获取具有特定postId的所有标记:

$sql = "
    SELECT pt.idPost, — select idPost first so it’s grouped by this col
           t.*
      FROM tags t JOIN poststags pt ON t.id=pt.idTag 
     WHERE pt.idPost IN (array of post ids)
";

$stmt=$db->prepare($sql);
$stmt->execute();

$tagsResult = $smt->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_OBJ);
//$tagsResult is now grouped by postId
//see https://stackoverflow.com/questions/5361716/is-there-a-way-to-fetch-associative-array-grouped-by-the-values-of-a-specified-c

foreach($postsResult as &$post) {

    if(isset($tagsResult[$post->id])) {
        $post->tags = $tagsResult[$post->id];
    }
    else {
        $post->tags = array();
    }   
}

您的解决方案只需稍加修改即可工作:
idPost
不能是唯一的,因为一篇文章最多可以有五个标记。删除
PDO::FETCH_UNIQUE
解决了它。再次感谢。