Php 如何以最少的查询次数获取帖子列表和相关标签
我的表格结构如下: 标记(更多类别):id、标记名称、描述、slug 帖子:id、标题、url POSTSTAGS:id、idPost、idTag 用户:id、用户名、userSlug 投票:id、idPost、idUser 每个帖子最多可以有五个标签,每个用户只能投票一次。目前,由于标记尚未实现,我使用以下查询检索分页结果集: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
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格式返回到angularjsng 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
解决了它。再次感谢。