【问题标题】:Optimize laravel query many-to-many cascade优化 laravel 查询多对多级联
【发布时间】:2021-09-04 02:06:58
【问题描述】:

我正在尝试优化我的查询,因为它需要很长时间才能执行。

我的模型由 6 个表组成,见 ER 图:

ER Schema

这是我的查询生成器:

 $events =  Event::orderBy('date','DESC')->with(['person', 'person.country', 'person.topics', 'train', 'station'])->get();

我也已经为不同的表建立了索引。

话题和人物之间有一个数据透视表:

public function topics()
    {
        return $this->belongsToMany(Topic::class, 'person_topic')->withPivot('quantity')->withTimestamps();
    }

有人可以帮我吗?

【问题讨论】:

    标签: php mysql laravel optimization


    【解决方案1】:

    当您在模型中使用即时加载时,它会将您的 eloquent 查询转换为许多 WhereIn 查询,例如下面的代码

    $books = Book::with('author')->get();
    
    foreach ($books as $book) {
        echo $book->author->name;
    }
    

    会被翻译成这两个查询:

    select * from books
    
    select * from authors where id in (1, 2, 3, 4, 5, ...)
    

    因此,根据您的查询,如果您想获取所有具有所有关系的实体,我建议您使用一些连接查询,而不是使用 Laravel 预加载。

    来自 laravel 文档的示例:

    DB::table('users')
                ->join('contacts', 'users.id', '=', 'contacts.user_id')
                ->join('orders', 'users.id', '=', 'orders.user_id')
                ->select('users.id', 'contacts.phone', 'orders.price')
                ->get();
    

    根据 ma​​tiaslauriti 评论,您还可以对查询进行一些分页,以便从数据库中逐块获取。

    样本:

    Flight::chunk(200, function ($flights) {
        foreach ($flights as $flight) {
            //
        }
    });
    

    还有一个Lazy 方法也可以完成相同的工作。

    【讨论】:

    • 我建议作者不要做原始查询,而是将->get()更改为paginate或使用take来限制模型数量......这是真正的问题,他是获得很多模型
    • 所以我的假设是他真的需要获取所有模型。但是是的,如果他的问题是内存不足,他应该使用一些分页或块方法。我也会将此部分添加到我的答案中,谢谢。
    • 即使他需要获取所有模型,当 Laravel 需要获取和加载 500 到 1k 的内存时,它的速度也很慢(PHP),而且他没有限制任何东西,所以这肯定是问题所在.我这样说是因为我必须处理报告,并且处理这些模型很痛苦,因为你知道在哪里,解决方案是分块。
    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-29
    相关资源
    最近更新 更多