查询Laravel / Eloquent中嵌套关系的最佳方法

时间:2019-02-26 09:35:13

标签: mysql laravel performance eloquent

我已经使用Laravel构建了一个应用程序,最终我拥有了很深的嵌套关系,有时我需要查询它们。数据库是MySQL。

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

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

浏览后,我发现有人建议采用以下方式解决嵌套关系:

onCreate

我喜欢代码很有意义,但性能却很糟糕。.super

的平均执行时间为 430ms

我重新编写了如下函数:

// 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');
            });
        });
    });
}

使用此代码,我平均执行时间为 4ms ,这显然要好得多。但是,在编写嵌套请求方面,这看起来也不太“方法”。

我真的很想了解:

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

1 个答案:

答案 0 :(得分:1)

首先,在不知道为什么会发生的情况下提高性能的好方法:)

问题1:为什么readers()-> get()比readersNew()-> get()

慢得多

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

您的readersNew()->get()在层次结构中向下遍历,这就是为什么它更快的原因。它首先根据匹配的权限提取目标组,然后提取与该组关联的用户身份,从而更快。

第二季度,最好的方式是编写此类请求

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);
}

我希望对您有帮助