【问题标题】:How to optimize Laravel Eloquent query design and relationships?如何优化 Laravel Eloquent 查询设计和关系?
【发布时间】:2018-07-25 16:43:23
【问题描述】:

我一直在尝试更多地了解如何更好地优化我的 eloquent 查询。我知道这涉及到拥有更强大的数据库设计并以“正确”的方式从服务器询问数据。

应用程序

我有一个示例应用程序,可让您添加任务列表、删除任务列表和编辑它们(主要是标题)。对于每个任务列表,您可以添加任务、删除任务和编辑任务。一个典型的 CRUD 应用。

守则

除非有要求,否则我不会发布我的 Vue 组件,因为我不确定它是否相关。我对初始查询优化更感兴趣。我的关系设置如下:

型号:User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

use App\Models\TaskList;
use App\Task;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'first', 'last', 'email', 'phone', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function lists() {
        return $this->hasMany(TaskList::class,'user_id');
    }
}

模型:TaskList.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

use User;
use App\Models\Task;

class TaskList extends Model
{
    protected $fillable = ['user_id','status','title'];

    public function user() {
        return $this->belongsTo(User::class);
    }

    public function tasks() {
        return $this->hasMany(Task::class,'list_id');
    }

    public function scopeLists() {
        return $this->where('user_id',auth()->user()->id);
    }
}

模型:Task.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

use App\Models\TaskList;
use App\User;

class Task extends Model
{
    public function list() {
        return $this->belongsTo(TaskList::class);
    }
}

控制器:TaskListController.php @index

public function index()
{
    $user = auth()->user()->load('lists.tasks');

    $data = [
        'lists' => $user->lists,
    ];        

    return view('user.tasklist',$data);
}

在我看来,我没有做任何特别的事情。只需将我的数据粘贴到我的 Vues 数组成员 lists

let app = new Vue({
        el: '#app',
        data: {
            lists: []
        }
    });

    @if(isset($lists))
        @foreach($lists as $list)
            app.lists.push({
                id: '{{ $list->id }}',
                title: '{!! addslashes($list->title) !!}',
                status: '{{ $list->status }}',
                tasks: JSON.parse('{!! $list->tasks !!}')
            });
        @endforeach
    @endif

问题

问题只是我的加载时间约为 1 秒。我在网上阅读了混合信息,称 Laravel 是一个缓慢的框架,其他人声称他们可以获得低于 20 毫秒的加载时间等等。诚然,我知道我在开发环境中,我将看到生产中的不同结果。我也知道我的开发包不一定会在生产中加载,这会改善引导。但我认为下面的这些数字非常缓慢,而且这里还有其他情况。

问题

简单地说,在这种情况下,我该如何提高性能并优化我的应用程序?

我想知道在这种特定情况下我可以采取哪些步骤来提高我的应用程序性能。在我的开发箱中,完全加载了我所有的开发包,我可以实现低于 500 毫秒的加载时间。即使是 500 毫秒似乎也很慢。可以达到Sub 200ms 或sub 100ms 吗?只是硬件问题吗?还是我对我的人际关系和负载完全错误?

"require": {
    "php": ">=7.1.3",
    "fideloper/proxy": "~4.0",
    "laravel/framework": "5.6.*",
    "laravel/tinker": "~1.0"
},
"require-dev": {
    "barryvdh/laravel-debugbar": "^3.1",
    "filp/whoops": "~2.0",
    "fzaninotto/faker": "~1.4",
    "mockery/mockery": "~1.0",
    "phpunit/phpunit": "~7.0",
    "symfony/thanks": "^1.0"
},

非常感谢任何对此优化的见解!

【问题讨论】:

  • 性能优化的第一条规则:度量。分析您的应用程序并找出最耗时的内容。没有通用的性能优化建议可以自动使任意应用程序更快。
  • 我实际上不知道该怎么做,但听起来是时候学习了。感谢您的提示。

标签: php laravel laravel-eloquent


【解决方案1】:

关于您的代码

据我所知,您正在以正确的方式查询数据库,您使用的是lazy eager loading,它执行的查询与预加载执行的查询完全相同。

您的数据库可能有问题。您没有发布迁移。 task_lists.user_idtasks.list_id 上的外键必须分别引用 user.idtask_lists.id

其他可能的原因

  • 您是说您的整个请求需要 1s,并且专注于查询,但您没有在 Laravel Debugbar 上显示实际查询时间。
  • 请注意:启动时间约为 600 毫秒,执行时间约为 300 毫秒。您的查询在执行时间内(还有许多其他事情)。
  • 引导时间主要受文件系统访问缓慢的影响,这是由常见的坏人 HDD 引起的。用 SSD 替换,您会发现有很大的改进。
  • 在调试模式下运行 Laravel Debugbar 的 Laravel 比在生产模式下要慢得多。这是因为启用了数据库查询记录器以及其他原因。
  • 如果你安装了php xdebug,它也会slow down your execution time
  • 在生产环境中从 Laravel 中删除您不使用的所有内容。不使用cookies?为什么加载CookieServiceProvider?不使用文件系统?为什么加载FilesystemServiceProvider?查看您的 app.providers 配置。这将减少启动时间,因为您将加载更少的文件。

好的,解决了所有这些问题,之后如何提高性能?

假设您的环境已优化,您的代码已优化,但您的响应时间仍然很慢,是时候Profile 您的代码了。使用right profiler tool,您将确切地看到哪段代码变慢了。

如果数据库查询本身很慢并且没有什么可以改进的,您可以将Laravel's Cache 与 memcached 或 redis 驱动程序一起使用,并缓存您的慢查询,而不是查询数据库以获取结果,它们将在内存中并在微秒内可用。

【讨论】:

  • 非常好,这正是我所希望的洞察力。我将四处修补,看看是否可以通过遵循您提出的要点来改善我的结果。不过,我将保留这个问题,因为我想看看其他人是否还有更多要补充的!再次感谢!
  • 祝你好运!优化是大多数开发人员不做的一项艰巨的工作,然后告诉其他需要更多基础设施的人。 :-(
猜你喜欢
  • 2017-11-14
  • 2018-05-27
  • 2021-07-22
  • 1970-01-01
  • 2017-10-07
  • 2013-10-03
  • 2017-07-19
  • 1970-01-01
  • 2020-09-24
相关资源
最近更新 更多