Mysql父子表减少数据库调用或在PHP中合并

时间:2012-01-13 19:34:12

标签: php mysql model-view-controller database-design

如果我有2个表,比如blog_category和博客,则每个“博客”只能属于特定类别,因此基于名为“blog_category_id”的键的1-1关系。

现在在我的代码中我会做类似的事情:

//Loop through categories such as 
foreach($categories as $cat):
//then for each category create an array of all its posts
$posts = $cat->getPosts(); // This would be another DB call to get all posts for the cat
//do stuff with posts
endforeach;

现在对我而言,根据$ categories的大小,这似乎在DB调用方面可能会相当昂贵。这仍然是最好的解决方案吗?或者我能够在代码中执行某些操作并首先检索所有类别,然后检索所有博客并通过ID以某种方式将它们映射到相应的类别?理论上这只是对DB的两次调用,现在大小合理,调用2(博客)的结果集肯定会更大,但实际的DB调用会不会很昂贵?

我通常会选择第一个选项,但我只是想知道是否会有更好的方法来处理这个问题,或者更有可能PHP的额外处理在性能方面会更昂贵?还特别是从MVC的角度来看,如果模型返回类别,但它也应该返回该类别的相应博客,我不知道如何最好地构建这个,从我的理解,不应该模型返回所有​​数据视图需要吗?

或者我最好在第一个查询中使用内部联接选择所有类别和博客并创建我需要的输出?也许通过使用多维数组?

由于

2 个答案:

答案 0 :(得分:1)

您可以使用简单的SQL查询来获取以下所有类别和帖子:

SELECT *
FROM posts p
JOIN categories c ON c.id = p.blog_category_id
ORDER BY c.category_name ASC,
         p.posted_date DESC

然后,当您循环返回的记录时,将当前类别ID分配给变量,您可以使用该变量与下一个记录类别进行比较。如果类别不同,则在打印记录之前打印类别标题。重要的是要注意,要使其工作,您需要先按类别排序,然后发布,以便同一类别中的所有帖子都在一起。

例如:

$category_id = null;
foreach($posts as $post) {
    if($post['blog_category_id'] != $category_id) {
        $category_id = $post['blog_category_id'];
        echo '<h2>' . $post['category_name'] . '</h2>';
    }
    echo '<h3>' . $post['post_title'] . '</h3>';
    echo $post['blog_content'];
}

注意:因为你还没有发布这两个表的模式,我必须编写类似于我希望在这样的代码中看到的列名。因此,如果没有进行一些调整,上面的代码将无法使用您的代码。

答案 1 :(得分:1)

最佳解决方案取决于您将如何处理数据。

延迟加载

在需要时加载数据。例如,当您拥有20个类别并且只为其中2个类别加载帖子时,这是一个很好的解决方案。但是,如果你需要为所有这些帖子加载帖子,它根本就没有效率......它被称为n + 1个查询(而且它真的很糟糕)。

急切加载

另一方面,如果您必须访问几乎所有帖子,则应该进行急切加载。

-- Load all your data in a query
SELECT *
FROM categories c
INNER JOIN posts p ON c.id = p.category_id;

// Basic example in JSON of how to format your result 
{
   'cat1': ['post1', 'post2'],
   'cat2': ['post5', 'post4', 'post5'],
   ...
}

怎么做?

在你的情况下,我会说一个急切的加载因为你在循环中加载所有东西。但是,如果您不能访问大部分数据,则应重新设计模型以执行延迟加载,以便在视图尝试访问时实际执行加载特定类别的帖子的SQL查询它们。

您怎么看?