使用访问器在Eloquent中进行慢速查询

时间:2019-03-14 20:47:56

标签: laravel eloquent

我有一个带有访问器的模型,该访问器获取与之相关的最后一个元素(通过另一个表/模型)。它对于单个查询很方便,但是现在我需要做一个总结,查询花费的时间太长。

该模型称为设备,它具有以下访问器:

public function getPreviousDeviceAttribute()
    {
        if ($this->pos_id > 0){
            $pos = Pos::find($this->pos_id);
            $device = $pos->devices()->newPivot()->where([
                    ['device_id', '<', $this->id],
                    ['pos_id','=', $this->pos_id]
                ])->get()->sortByDesc('id')->first();
            return $device;
        } else {
            return null;
        }

    }

我需要从Controller查询集合的所有previous_device。

这是查询:

$c_pendientes = Device::whereNotNull('fecha_instalacion')
                ->whereNull('fecha_reversa')
                ->where('pos_id', '>', 0)
                ->where('customer_id', 1)
                ->get();

$pendientes = $this->seriesPendientes($c_pendientes);

public function seriesPendientes($pendientes)
    {
        $count = 0;

        foreach($pendientes as $device)
        {

            $prev = $device->previous_device;
            if($prev instanceof App\Device)
            {
                if(is_null($prev->fecha_reversa))
                {
                    $count++;

                }
            }
        }
        return $count;
    }

编辑:

属性:

设备

`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `serial` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `rotulo` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `code` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `cost_center` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `guia_recepcion` INT(11) NULL DEFAULT NULL,
    `guia_reversa` INT(11) NULL DEFAULT NULL,
    `pep` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `modified_by` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `modified_on` DATETIME NULL DEFAULT NULL,
    `fecha_recepcion` DATETIME NULL DEFAULT NULL,
    `fecha_instalacion` DATETIME NULL DEFAULT NULL,
    `fecha_reversa` DATETIME NULL DEFAULT NULL,
    `status_id` INT(10) UNSIGNED NOT NULL,
    `location_id` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `customer_id` INT(10) UNSIGNED NOT NULL,
    `str_id` INT(10) UNSIGNED NOT NULL,
    `model_id` INT(10) UNSIGNED NOT NULL,
    `pos_id` INT(11) NOT NULL,
    `user_id` INT(10) UNSIGNED NOT NULL,
    `technician_id` INT(10) UNSIGNED NOT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL
)

位置

CREATE TABLE `pos` (
    `id` INT(11) NOT NULL,
    `vigente` BLOB NOT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)

关系

CREATE TABLE `devices_pos` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `device_id` INT(10) UNSIGNED NOT NULL,
    `pos_id` INT(10) UNSIGNED NOT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)

1 个答案:

答案 0 :(得分:0)

如果要为大型集合中的每个项目调用此getter,则$pos = Pos::find($this->pos_id);行将为每个项目执行一个请求。如果尚不存在以下关系,则可以通过定义以下关系来避免它

public function pos()
{
   return $this->belongsTo(Pos::class);
}

然后急于加载此关系(一个请求所有项):

$c_pendientes = Device::with('pos')
                ->whereNotNull('fecha_instalacion')
                ->whereNull('fecha_reversa')
                ->where('pos_id', '>', 0)
                ->where('customer_id', 1)
                ->get();

您可能也应该像这样:eagder加载pos.devices。

$c_pendientes = Device::with('pos')
                ->with('pos.devices')
                ->whereNotNull('fecha_instalacion')
                ->whereNull('fecha_reversa')
                ->where('pos_id', '>', 0)
                ->where('customer_id', 1)
                ->get();

让我知道是否有帮助。