为了账号安全,请及时绑定邮箱和手机立即绑定

Laravel - 在刀片中加载更多结果时如何避免 N+1 问题?

Laravel - 在刀片中加载更多结果时如何避免 N+1 问题?

PHP
慕的地6264312 2021-12-24 15:30:50
我正在建立一个有提交的网站,这些提交有评论。这些评论的结构很像 reddit 的结构。这是一张图片供参考:这些评论有很多关系(是否有 auth 用户保存/赞成/反对评论,评论是否有孩子,谁创建了评论)。所以为了避免一堆不必要的服务器查询,我急切地加载这些关系。$comments = Comment::with(['children','owner','savedComments','votes'])                    ->where('submission_id', $submission->id)                    ->where('parent_id', NULL)                    ->orderBy('removed','asc')                    ->orderBy($sortBy, $direction)                    ->paginate(200);然后我foreach在视图中查看这些评论。但是,请注意在我的查询中我只加载父评论。对于孩子,我foreach通过评论的children关系加载他们。评论.php:public function children() {    return $this->hasMany('App\Comment','parent_id')->orderBy('total_score', 'desc');}   comment_block.blade.php:@foreach ($comment->children as $comment)    @if ($loop->depth == 10)        <div>            <a href="{{ route('get.submission', ['subchan' => $submission->subchan, 'id' => $submission->id, 'URLtitle' => $submission->URL_title,'commentID' => $comment->parent_id]) }}">Continue this thread</a>        </div>        @break    @elseif ($loop->iteration == 8 && $totalComments >= 25)         <div class="loadMoreReplies"        data-submission-id="{{ $submission->id }}"        data-parent-id="{{$comment->parent_id}}"        >Load More Replies (<span id="remaining-reply-count-{{$comment->parent_id}}">{{ $loop->remaining + 1 }}</span>)</div>        @break          @else        <div class="comment-container comment-container-child" id="comment-container-{{$comment->id}}">            @include('partials.comment_block')        </div>    @endif@endforeach问题在于,尽管父评论关系是急切加载的,但每个子评论也会引起查询,因为它们是通过关系加载到视图中的。所以我的服务器查询总数从一个增加到可能数百个。我该如何解决这个问题?
查看完整描述

2 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

你的数据库是什么?如果您的数据库支持公共表表达式,则可以将递归数据优化为单个查询。但是 Laravel 不支持这些。您将不得不创建原始查询。

如果您的数据库不支持 CTE(公用表表达式),那么您能做的最好的事情就是分别加载每个递归级别 @Tim Lewis 对 @Felix Maxime 的评论回答很好地涵盖了该用例。


查看完整回答
反对 回复 2021-12-24
?
倚天杖

TA贡献1828条经验 获得超3个赞

似乎没有办法在与 Laravel 的递归中预先加载嵌套关系,或者至少在这种情况下没有(尝试在多个地方询问,而不仅仅是 stackoverflow)。

因此,为了解决我的问题,我将以正常方式加载所有父评论及其关系,但仅将子评论作为数据加载,然后使用 AJAX 调用填充它们。这只会添加一个服务器查询。


查看完整回答
反对 回复 2021-12-24
  • 2 回答
  • 0 关注
  • 177 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号