代码之家  ›  专栏  ›  技术社区  ›  Kevin Pimentel

如何优化Laravel雄辩的查询设计和关系?

  •  1
  • Kevin Pimentel  · 技术社区  · 6 年前

    我一直在努力学习如何更好地优化我雄辩的查询。我知道这涉及到更健壮的数据库设计和以“正确”的方式从服务器请求数据。

    应用程序

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

    enter image description here

    代码

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

    型号: 使用者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');
        }
    }
    

    型号: 任务列表。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);
        }
    }
    

    型号: 任务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 @索引

    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毫秒的加载时间等等。当然,我知道我在开发环境中,我将看到生产的不同结果。我还了解到,我有一些开发包,这些包不一定要在生产中加载,这将改进引导。但我认为下面的数字相当缓慢,这里还有其他一些事情。

    enter image description here

    enter image description here

    问题是

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

    我想知道在这个特定场景中我可以采取哪些步骤来提高我的应用程序性能。在我的开发盒中,完全加载了我的所有开发包,我可以实现低于500毫秒的加载时间。即使500毫秒似乎也很慢。能否达到小于200ms或小于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"
    },
    

    非常感谢您对此进行优化!

    1 回复  |  直到 6 年前
        1
  •  2
  •   Elias Soares    6 年前

    关于您的代码

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

    您的数据库可能有一些问题。您没有发布迁移。必须打开外键 task_lists.user_id tasks.list_id 引用到 user.id task_lists.id 分别地

    其他可能的原因

    • 你是说你的整个请求 1秒 ,并将重点放在查询上,但您没有在Laravel调试栏上显示实际的查询时间。
    • 请注意:引导时间约为600ms,执行时间约为300ms。您的查询在执行时间内(以及许多其他内容)。
    • 引导时间主要受文件系统访问速度慢的影响,这是由常见的坏蛋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驱动程序,并缓存出您的慢速查询,因此它们将在内存中,在微秒内可用,而不是在数据库中查询结果。