【问题标题】:How to find related pages without querying inside a loop?如何在不循环内查询的情况下找到相关页面?
【发布时间】:2013-05-17 23:57:46
【问题描述】:

我正在编程的网站有问题。在我有页面和子页面的网站部分上,事情有点慢。 这部分我有很多 mySQL 查询,有 20 多个查询同时执行, 让我等待最多 5 秒钟,直到出现任何东西。

我读了这个问题Is 20 SQL Queries per page load really considered a lot? 并发现我确实有问题......而madlep 的回答提到了这种N+1 的情况,我在foreach 中为每个页面查询数据库,寻找它的孩子。

这是一个例子(顺便说一下,我使用的是 Laravel):

 $pages = Page::where('slug', '=', $slug)->get(array('id', 'title', 'slug'));
 foreach ($pages as $page) {
    $children = Page::where('parent_id', '=', $page->id)->get(array('id', 'title', 'slug'));
    foreach ($children as $child) {
        $grandChildren = Page::where('parent_id', '=', $child->id)->get(array('id', 'title', 'slug'));
    }
 }

作为一个新手,我正在努力寻找一种更好的方法来处理这个问题,减少页面查询。

问题是:如何在 foreach 循环之外获取子页面?一切都是动态完成的,所以我需要一种灵活的方法来处理这个问题。

【问题讨论】:

    标签: mysql sql performance webpage


    【解决方案1】:

    首先,由于您跟踪的项目数量相对较少(例如网页),因此我将从保存整个层次结构的缓存数据结构中提取这些数据结构,并且可以在 RAM 中进行查询,而不是发出数据库查询。您可以在应用程序启动时构建此缓存结构,如果您经常更改页面,则可以通过任务/作业定期重建它。但是,如果这不是一个选项,您确实需要重写整个 SQL 查询,将完整记录集的返回作为单个 SET OPERATION 执行,而不是使用代码逻辑执行多个查询。您的 ORM 可能有办法处理 N+1,但通常它们会告诉您重写查询或重组表以避免 N+1。

    缓存结构示例 字典形式为:CurrentPageId, ParentPageId

    ParentPageId 为 null 的任何页面都是根级页面。

    【讨论】:

    • 这对我帮助很大。非常喜欢。我现在正在使用 Laravel 缓存,事情变得更快了。只有一个缺点:当用户更新或插入内容时,他将不得不等到缓存过期。我想知道像 StackOverflow 这样的大型网站如何处理这个问题。数据库发生变化时如何维护缓存并使其重建?
    • 通常,您的 ORM 缓存会处理针对数据库的所有流量,因此“通过”ORM 的更新和插入已经被跟踪。如果您是直接修改数据库(而不是通过 ORM),那么您实际上是在与框架作斗争。如果您只是在测试中注意到这一点,并且不打算在数据库投入生产后通过数据库进行临时插入/更新,那么没有理由真正担心它。
    猜你喜欢
    • 2014-09-26
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 2014-08-25
    • 1970-01-01
    相关资源
    最近更新 更多