【问题标题】:Eloquent taking too long with remote MySQL DB雄辩的远程 MySQL 数据库耗时太长
【发布时间】:2018-07-26 15:32:49
【问题描述】:

我正在开发一个 Web (Laravel) 和 iOS 应用程序,它们都使用我也在使用 Laravel 开发的 REST API。来自 AWS RDS 实例上托管的 MySQL 数据库的 API 查询。

当我在 localhost 上设置 API 和应用程序,以及配置为连接我的本地数据库(与应用程序和 API 相同的机器)的 API 时,它按预期工作,但问题是当我设置 API 时从 AWS RDS 数据库而不是本地查询。 使用 eloquent 进行的简单查询,例如

Product::where('brand_id', '=', $id)
               ->get()

大约需要 10 到 15 分钟才能完成,但如果我使用查询生成器执行相同的查询,例如;

DB::select('select * from products where brand_id = ?', [$id]);

工作正常。

直接在 MySQL 上执行查询或在 Laravel Tinker 上运行 Product::all() 与本地 API / 远程数据库设置一样工作。

编辑:

这是我执行SHOW CREATE TABLE products时得到的结果

CREATE TABLE `products` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `SKU` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `price` double(8,2) NOT NULL,
  `description` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `product_details` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `material_and_care` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `material` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `care` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `colors` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `made_in` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `size_chart` text COLLATE utf8mb4_unicode_ci,
  `size_chart_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `brand_id` int(10) unsigned NOT NULL,
  `category_id` int(10) unsigned NOT NULL,
  `published` tinyint(1) NOT NULL DEFAULT '0',
  `featured` tinyint(1) NOT NULL DEFAULT '0',
  `promo_title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `promo_caption` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `shipping_height` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `shipping_width` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `shipping_length` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `shipping_weight` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `is_vertical` tinyint(1) NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `products_category_id_foreign` (`category_id`),
  KEY `products_brand_id_foreign` (`brand_id`),
  CONSTRAINT `products_brand_id_foreign` FOREIGN KEY (`brand_id`) REFERENCES `brands` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `products_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `subcategories` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=501 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

我的产品型号:

class Product extends Model
{
    use SoftDeletes, CascadeSoftDeletes;

    protected $cascadeDeletes = [
        'items',
        'options',
        'images',
        'sizes'
    ];

    protected $fillable = [
        'sku',
        'name',
        'price',
        'description',
        'product_details',
        'material_and_care',
        'material',
        'color_1',
        'color_2',
        'color_3',
        'care',
        'made_in',
        'size_chart',
        'size_chart_url',
        'brand_id',
        'category_id',
        'published',
        'featured',
        'promo_title',
        'promo_caption',
        'shipping_weight',
        'shipping_height',
        'shipping_width',
        'shipping_length',
        'is_vertical'
    ];

    protected $appends = [
        'interests',
        'brand',
        'options',
        'sizes',
        'items',
        'images',
        'comment_count',
        'discount',
        'suits_me_count'
    ];

    protected $hidden = [
        'created_at',
        'deleted_at',
        'updated_at',
        'subcategory'
    ];

    protected static function boot()
    {
        parent::boot();
        static::addGlobalScope(new PublishedProductScope);
    }

    public function getDiscountAttribute() {
        return $this->discount()->first();
    }

    public function getSuitsMeCountAttribute() {
        return $this->suitsmes()->count();
    }

    public function getCommentCountAttribute() {
        return $this->comments()->count();
    }


    public function getImagesAttribute(){
        return $this->images()->pluck("url");
    }

    public function getInterestsAttribute() {
        return $this->interests()->get();
    }

    public function getBrandAttribute(){
        return $this->brand()->first();
    }

    public function getOptionsAttribute(){
        return $this->options()->get();
    }

    public function getSizesAttribute(){
        return $this->sizes()->get();
    }

    public function getItemsAttribute(){
        return $this->items()->get();
    }

    public function interests() {
        return $this->belongsToMany('App\Interest', 'product_interest');
    }

    public function brand() {
        return $this->belongsTo('App\Brand');
    }

    public function options() {
        return $this->hasMany('App\ProductOption');
    }

    public function sizes() {
        return $this->hasMany('App\ProductSize');
    }

    public function items() {
        return $this->hasMany('App\ProductItem');
    }

    public function images() {
        return $this->hasMany('App\ProductImage');
    }

    public function comments() {
        return $this->hasMany('App\ProductComment');
    }

    public function suitsmes() {
        return $this->belongsToMany('App\User', 'wishlist', 'product_id', 'user_id');
    }

    public function discount(){
        return $this->hasOne('App\Discount');
    }

    public function category() {
        return $this->belongsTo('App\Subcategory', 'category_id');
    }

}

还有我的品牌模型:

class Brand extends Model
{


 protected $fillable = [
        'first_name',
        'last_name',
        'email',
        'phone_number',
        'birth_date',
        'ssn',
        'street_address',
        'street_address_2',
        'city_address',
        'state_address',
        'postal_code_address',
        'legal_name',
        'dba',
        'tax_id',
        'street_business_address',
        'street_business_address_2',
        'city_business_address',
        'state_business_address',
        'postal_code_business_address',
        'destination_fund',
        'email_business',
        'phone_number_business',
        'account_number_fund',
        'routing_number_fund'
    ];

    protected $hidden = [
        'created_at',
        'deleted_at',
        'updated_at'
    ];

    protected $appends = [
        'images'
    ];

    public function getImagesAttribute()
    {
        return $this->images()->get();
    }

    public function getBillboardPicturesAttribute() {
        $pictures = [$this->billboard, $this->billboard2, $this->billboard3, $this->billboard4];
        return $pictures;
    }    

    public function users()
    {
        return $this->belongsToMany('App\User', 'user_brand_role', 'brand_id', 'user_id');
    }

    public function getInterestsAttribute() {
        return $this->interests()->pluck('interest_id');
    }

    public function interests() {
        return $this->belongsToMany('App\Interest', 'brand_interest', 'brand_id', 'interest_id');
    }

    public function products() {
        return $this->hasMany('App\Product');
    }

    public function images() {
        return $this->hasMany('App\BrandImage');
    }

    public function categories() {
        return $this->hasMany('App\Category');
    }

    public function getCatalogAttribute() {
        return $this->categories()->orderBy('name', 'asc')->get();
    }


}

【问题讨论】:

  • 哇,看起来很奇怪,试试Product::where(array("product_id"=>$id)) ->get()。我正在使用 RDS,但我没有任何问题。
  • 如果您的brand_id 不是primary_key,那么您需要在brand_id 字段上应用索引。
  • 其他表有同样的问题吗?如果没有,请重新启动您的服务器。
  • 您是否对Product 模型中配置的任何关系进行了默认预加载?
  • 你可以试试。它在修补程序中运行良好的事实让我认为在您的请求响应周期中发生了其他事情,这会减慢它的速度。

标签: mysql laravel rest amazon-web-services eloquent


【解决方案1】:

问题在于您的Product 模型中的这段代码:

protected $appends = [
    'interests',
    'brand',
    'options',
    'sizes',
    'items',
    'images',
    'comment_count',
    'discount',
    'suits_me_count'
];

这些属性是关系,因此它们会导致多个 每次 Eloquent 读取/返回一行时加入。

此查询:DB::select('select * from products where brand_id = ?', [$id]); 不会产生任何连接,并且是来自单个表的选择查询。这就是为什么当您比较结果时,您会发现查询时间存在巨大差异。

有两种可能的解决方案:

1.删除附加项

删除附加,当您需要关系时,请使用 with 函数

2。隐藏附加属性

您可以将此代码添加到您的 Product 模型中:

protected $hidden = [
    'created_at',
    'deleted_at',
    'updated_at',
    'interests',
    'brand',
    'options',
    'sizes',
    'items',
    'images',
    'comment_count',
    'discount',
    'suits_me_count'
];

当您需要一个属性时,只需使用$product->makeVisible('property_name')。否则,默认情况下,不会加载或查询这些属性

【讨论】:

  • 为什么它会在 tinker 中正常运行?
  • 不确定,可能有很多原因。也许brand_id 25 具体没有任何关系,或者它没有很多产品。我不认为测试是苹果对苹果。不管是什么情况,代码几乎都表明这些关系正在被加载,因此导致了多个连接,所以我很确定这是真正的原因
  • 有趣,我不知道appends 功能。
  • $appends 中的属性仅适用于将模型转换为数组 (toArray()) 或 JSON (toJson()) 时。可能在 Tinker 中它没有运行这样的转换,但在应用程序中被传递给视图或被这样转换。
  • 你是对的。我一评论附加内容,一切就开始变得更流畅了。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
相关资源
最近更新 更多