php - soporta - ¿Por qué el modelo de Laravel duplica el conjunto de datos y cómo(si es posible) tener solo un conjunto de datos?
optimizar consultas mysql explain (3)
Es conveniente que el modelo laravel proporcione un método que pueda devolver resultados de otra tabla asociada.
Por ejemplo, tengo una tabla llamada artículo y otra tabla llamada comentarios, donde la tabla de comentarios almacena los comentarios de un artículo en la tabla de artículos. Entonces, para obtener todos los comentarios del ítem con id 1, lo haré:
Item::find(1)->feedback;
Y a continuación, la impresión del objeto devuelto.
Illuminate/Database/Eloquent/Collection Object
( [items:protected] => Array
(
[0] => Feedback Object
(
[table:protected] => feedback
[connection:protected] =>
[primaryKey:protected] => id
[perPage:protected] => 15
[incrementing] => 1
[timestamps] => 1
[attributes:protected] => Array
(
[id] => 1
[rma_id] => 3
[item_id] => 8
[quo_id] => 0
[case_id] => i2eM20160120
[line_no] => 000001
[content] => test
[status] => sent
[read] => 0
[sender] => Tester
[created_at] => 2016-01-20 18:03:44
[updated_at] => 2016-01-20 18:03:44
)
[original:protected] => Array
(
[id] => 1
[rma_id] => 3
[item_id] => 8
[quo_id] => 0
[case_id] => i2eM20160120
[line_no] => 000001
[content] => test
[status] => sent
[read] => 0
[sender] => Tester
[created_at] => 2016-01-20 18:03:44
[updated_at] => 2016-01-20 18:03:44
)
[relations:protected] => Array
(
)
[hidden:protected] => Array
(
)
[visible:protected] => Array
(
)
[appends:protected] => Array
(
)
[fillable:protected] => Array
(
)
[guarded:protected] => Array
(
[0] => *
)
[dates:protected] => Array
(
)
[touches:protected] => Array
(
)
[observables:protected] => Array
(
)
[with:protected] => Array
(
)
[morphClass:protected] =>
[exists] => 1
)
)
)
Funciona bien, y muestra que solo hay una retroalimentación en el elemento con id 1.
Lo que me preocupa es que el conjunto de datos está duplicado en [attributes:protected]
y [original:protected]
. Este es solo un caso de prueba y el caso real consistirá en miles de comentarios y tener un conjunto de datos duplicados es una gran pérdida de memoria. El conjunto de datos no está duplicado si DB::table(''table_name'')
enfoque DB::table(''table_name'')
, pero eso es mucho menos conveniente.
¿Por qué laravel necesita duplicar los datos en el modelo?
¿Y hay una forma de hacer que devuelva solo un conjunto de datos?
Actualmente estoy usando ->toArray()
para recortar los datos innecesarios justo después de la consulta, pero el uso de la memoria todavía está allí porque laravel aún está creando ese conjunto de datos.
Si bien es difícil obtener un buen ejemplo, te permite establecer atributos antes de guardarlos definitivamente. Probablemente sea bueno si pasas por muchas funciones y finalmente compruebas si todo se ha configurado correctamente para el guardado final sin la necesidad de almacenar todo en variables separadas.
Muy pequeño ejemplo:
$user = User::find(1);
print_r($user);
$user->name = ''John Doe'';
print_r($user);
$user->save();
print_r($user());
Devuelve algo como:
Primera impresión:
[attributes:protected] => Array
(
[id] => 1
[name] => ''Jimmy Doe''
...
)
[original:protected] => Array
(
[id] => 1
[name] => ''Jimmy Doe''
...
)
Segunda impresión:
[attributes:protected] => Array
(
[id] => 1
[name] => ''John Doe''
...
)
[original:protected] => Array
(
[id] => 1
[name] => ''Jimmy Doe''
...
)
Impresión Thrid:
[attributes:protected] => Array
(
[id] => 1
[name] => ''John Doe''
...
)
[original:protected] => Array
(
[id] => 1
[name] => ''John Doe''
...
)
Solo después de guardar () los datos se están guardando en la base de datos.
SyncOriginal () de Eloquent se activa cuando un modelo es save () ''d:
/**
* Sync the original attributes with the current.
*
* @return $this
*/
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
Los datos originales se almacenan para permitir que el modelo realice una verificación sucia. La comprobación sucia se usa internamente para manejar las actualizaciones de la base de datos.
Si un modelo no está sucio e intenta guardarlo, no se realizará ninguna actualización. Si un modelo está sucio e intenta guardarlo, solo se actualizarán los campos que estén sucios.
Si realmente deseaba deshacerse de esto, podría anular los syncOriginal()
y syncOriginalAttribute()
en el modelo. Si hicieras esto, sin embargo, significaría que el modelo siempre se considerará sucio. getDirty()
siempre devolverá todos los atributos, y isDirty()
siempre devolverá true
.
Si usa marcas de tiempo, también deberá anular el método updateTimestamps()
, de lo contrario, sus campos updated_at
y created_at
nunca se establecerán.
class Feedback extends Model
{
// ...
public function syncOriginal()
{
return $this;
}
public function syncOriginalAttribute($attribute)
{
return $this;
}
protected function updateTimestamps()
{
$time = $this->freshTimestamp();
$this->setUpdatedAt($time);
if (! $this->exists) {
$this->setCreatedAt($time);
}
}
// ...
}
Puede haber otras repercusiones que no son evidentes de inmediato al revisar el código.
Sin embargo, una vez dicho todo esto, si tiene esta preocupación por la memoria, es posible que necesite reflexionar un momento acerca de su enfoque y de lo que está tratando de hacer. ¿De verdad necesitas cargar miles de comentarios a la vez? ¿Es esta una operación que se puede chunk
? ¿Este trabajo sería mejor atendido por trabajos individuales en una cola? etc ...
Esto no debería ser un problema teniendo en cuenta cómo PHP funciona internamente. A menos que los ''atributos'' no se modifiquen, ''atributos'' es solo un puntero al ''original'' (o al revés), por lo que tener ambas matrices ocupa casi la misma cantidad de memoria que tener solo una de ellas. Esta es la razón por la que el uso de la memoria no cambia cuando lo haces con toArray()
.
Por favor, consulte este enlace para más detalles: http://blog.ircmaxell.com/2014/12/what-about-garbage.html