【问题标题】:Best way to query nested relationships in Laravel/Eloquent在 Laravel/Eloquent 中查询嵌套关系的最佳方法
【发布时间】:2019-02-26 09:35:12
【问题描述】:

我已经使用 Laravel 构建了一个应用程序,我最终在其中建立了相当深的嵌套关系,有时我需要查询这些关系。数据库是 MySQL。

例如,我想检索所有允许阅读书籍用户。我的数据结构如下:

  • 一个 User 通过一个 UserMembership 属于 0-n 个 UserGroups
  • 一个用户组有0-n个权限
  • 权利与 1 相关,并描述了可以执行的操作

查看浏览后发现有人推荐如下解决嵌套关系的方法:

// class Book extends Model
public function readers() {
    $bookId= $this->id;
    return User::whereHas('memberships', function($m) use($bookId) {
        $m->whereHas('group', function($g) use($bookId) {
            $g->whereHas('rights', function($r) use($bookId) {
                $r->where('resource_id', $bookId)->where('action', 'read');
            });
        });
    });
}

我喜欢这段代码很有意义,但性能很糟糕。Book::find(967)->readers()->get()的平均执行时间为 430ms

我重写了函数如下:

public function readersNew() {
    $bookId= $this->id;
    $g = Right::where('resource_id', $bookId)->where('action', 'read')->pluck('group_id');
    $uIds = UserMembership::whereIn('group_id', $g)->pluck('user_id');
    return User::whereIn('id', $uIds);
}

使用这段代码,我实现了 4ms 的平均执行时间,这显然要好得多。但这在编写嵌套请求方面看起来也不那么“有条理”。

我真的很想了解:

  • 为什么 readers()->get()readersNew()->get() 慢很多
  • 最好的方法是编写此类请求

【问题讨论】:

  • 既然“最佳方式”确实是由生成的SQL决定的,请给我们看看。

标签: mysql laravel performance eloquent


【解决方案1】:

首先,在不知道为什么会发生的情况下提高性能的工作做得很好:)

Q1:为什么 reader()->get() 比 readerNew()->get() 慢很多

您的readers()->get() 函数在层次结构中自上而下遍历,这就是为什么它更有意义但速度较慢的原因。它与运行 3 个 foreach 嵌套循环相同,它首先返回所有具有成员资格的用户,然后为每个用户迭代并找到其所属的所有组,然后迭代每个组并找到每个组的权限,然后迭代每个权限并获得通过匹配 resource_id 和 action 获得所需的条目。

而您的readersNew()->get() 在层次结构中自下而上遍历,这就是它更快的原因。它首先根据匹配的权限提取目标组,然后提取与该组关联的成员资格、用户,因此速度更快。

Q2 编写此类请求的最佳方式是什么

readersNew()->get() 的方法是最好的,如果你愿意,你可以改变你的写作惯例以使其更有意义:

public function readersNew() {
    $bookId= $this->id;
    $targetGroup = Right::where(['resource_id' => $bookId, 'action' => 'read'])->pluck('group_id');
    $associatedUserIds = UserMembership::whereIn('group_id', $g)->pluck('user_id');
    return User::whereIn('id', $associatedUserIds);
}

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-19
    • 2019-02-26
    • 1970-01-01
    • 2015-06-27
    • 2019-01-30
    相关资源
    最近更新 更多