Php 如何在Laravel雄辩的便捷附件上提高数据库性能?

Php 如何在Laravel雄辩的便捷附件上提高数据库性能?,php,mysql,laravel,laravel-5,eloquent,Php,Mysql,Laravel,Laravel 5,Eloquent,因此,Laravel的$appends是一个非常好的特性。我有一个产品表,我在$appends数组中添加了供应商、图像和其他内容,因此我的代码如下所示: 类产品扩展\ResourceModel{ protected $appends = ['vendor', 'images']; function getVendorAttribute() { return $this->vendor()->first(); } function getImages() { $th

因此,Laravel的
$appends
是一个非常好的特性。我有一个
产品
表,我在
$appends
数组中添加了
供应商
图像
和其他内容,因此我的代码如下所示:

类产品扩展\ResourceModel{

protected $appends = ['vendor', 'images'];

function getVendorAttribute() {
    return $this->vendor()->first();
}

function getImages() {
    $this->_images = $this->images()->get();
}
整洁,嗯

但是,并非如此,下面是这段整洁的代码正在执行的查询列表:

select * from `products`;
select * from `images` where `images`.`imageable_id` = 1 and `images`.`imageable_type` = 'Product';
select * from `vendors` where `vendors`.`id` = 1;
select * from `images` where `images`.`imageable_id` = 2 and `images`.`imageable_type` = 'Product';
select * from `vendors` where `vendors`.`id` = 2;
select * from `images` where `images`.`imageable_id` = 3 and `images`.`imageable_type` = 'Product';
select * from `vendors` where `vendors`.`id` = 3;
select * from `images` where `images`.`imageable_id` = 4 and `images`.`imageable_type` = 'Product';
select * from `vendors` where `vendors`.`id` = 4;
select * from `images` where `images`.`imageable_id` = 5 and `images`.`imageable_type` = 'Product';
select * from `vendors` where `vendors`.`id` = 5;
当然,我宁愿做:

select * from `products`;
select * from `images` where `images`.`imageable_id` in (1, 2, 3, 4, 5) and `images`.`imageable_type` = 'Product';
select * from `vendors` where `vendors`.`id` in(1, 2, 3, 4, 5);
甚至是
连接
等效项

因此,我的详细问题如下:

1) 我在20页中加载产品。这会生成大约41个查询(实际上,为了这个问题,我对其进行了简化)。我认为这真的会损害性能,对吗?对于一个平均的MySQL盒,第一种类型的41个简单查询确实比第二种类型的3个查询更耗时

2) 在我疯狂修复所有应用程序逻辑之前,是否有一种捆绑(或打包,或简单)的方式在Laravel上实现这一点


提前感谢!

您应该立即加载查询并将访问器修改为以下内容:

function getVendorFirstAttribute() {
   $vendors = $this->vendor;
   return $vendors->shift();
}

function getImagesAllAttribute() {
    return $this->images;
}

问题在于,您的方法正在使用关系查询,因此每次访问它们时,它们都会运行一个新的查询,并且没有利用任何延迟或急切的加载

您可以通过确保急切地加载关系并访问方法中的关系属性(
$this->vendor
vs
$this->vendor()
)来解决此问题,但您需要重命名
getVendorAttribute()
方法,以便它不会与关系属性冲突

但是,我认为您可能要查找的是模型上的
$with
属性。如果您在模型上设置
$with
属性,则属性列出的关系将始终渴望加载该模型。此外,由于这些关系将始终存在,因此当模型转换时,它们将始终存在ted添加到数组中,无需向
$appends
属性添加任何内容

所以,你的班级看起来像:

class Product extends Model {

    // always eager load the vendor and images relationships
    protected $with = ['vendor', 'images'];

    // relationship to the vendor
    public function vendor()
    {
        return $this->belongsTo(Vendor::class);
    }

    // relationship to the images
    public function images()
    {
        return $this->hasMany(Image::class);
    }
}
在上面的类中,如果要在已加载的
产品
实例上调用
toArray()
toJson()
,则输出将包括相关的
供应商
和相关的
图像


对于额外的阅读,我建议阅读和。

Laravel的附录不够聪明,无法做到开箱即用。您可以使用
查询范围自己创建此功能。
。事实上,我永远不会向根据任何类型的查询构建的模型添加任何内容。只有格式化程序等。您的
getVendorAttribute()
方法将覆盖
供应商
关系属性,在方法内调用
$this->vendor
将导致“未定义属性”错误。此外,关于关系属性,
$this->vendor
将已经包含相关的供应商记录,并调用
first()
,它将实际运行一个新的查询并返回数据库中的第一个供应商记录。