Мне нужно обновить каждую строку моей таблицы, связанную с моделью MyModel. Каждое обновление требует выполнения PHP-кода. В моем случае это не проблема, но мне было интересно, как это сделать более эффективно?
MyModel::chunk(1000, function (Collection $collection) {
foreach ($collection as $model) {
$pascalCaseModelName = $model->modelName;
$myModel->modelAlias = Str::snake($pascalCaseModelName);
$myModel->save();
}
});
Сейчас я сохраняю каждую модель после обработки. Это означает, что запрос к базе данных выполняется для каждой модели. Интересно, можно ли сохранить целый фрагмент с помощью оператора on, который вместо этого запускает один запрос к базе данных.
Единственное решение, которое я смог найти, это метод saveMany. Но это применимо только к отношениям.
@TimLewis да, это просто «заполнить» недостающие данные, и производительность не проблема. Мне просто любопытно, предоставляет ли Laravel функции для этого.
@ Тимо, я бы просто сделал $collection->each() вместо MyModel::chunk(1000,). Коллекция уже может проходить по каждой записи, не нужно чанковать
Попался. Методы Laravel, как правило, фокусируются на одной модели, и save() выполняет UPDATE запрос для этой конкретной строки через UPDATE ... WHERE id = .... Вы можете попытаться разбить обновления на части и выполнить их все в одном операторе (или в нескольких, IIRC есть ограничение). Но опять же, все это на самом деле только фактор, если производительность является проблемой.






Вы пробовали это?
MyModel::chunk(1000, function (Collection $collection) {
$updates = [];
foreach ($collection as $model) {
$pascalCaseModelName = $model->modelName;
$updates[] = [
'id' => $model->id,
'model_alias' => Str::snake($pascalCaseModelName),
];
}
if (!empty($updates)) {
DB::table('my_models')->update($updates, 'id');
}
});
Спасибо за предложение. Отличная идея! Посмотрите на мой собственный ответ, я использовал метод upsert, чтобы заставить код работать.
По предложению Захариаса мне удалось решить проблему. Но я использовал метод upsert вместо update.
MyModel::chunk(1000, function (Collection $collection) {
$updates = [];
foreach ($collection as $model) {
$pascalCaseModelName = $model->modelName;
$updates[] = [
'id' => $model->id,
'model_alias' => Str::snake($pascalCaseModelName),
];
}
DB::table('my_models')->upsert(
$updates,
['id'],
['model_alias']
);
});
Хотя update может обновлять несколько записей, он не может вставлять разные значения для каждой модели. может. Смотрите https://laravel.com/docs/10.x/queries#upserts
Привет, мне интересно, как это работает? $updates[] = [ 'id' => $model->id, 'model_alias' => Str::snake($pascalCaseModelName), ]; не будет ли значение переменной $updates заменяться на каждой итерации? или это то же самое, что и array_push()?
@YusufGiovanno Да, это то же самое, что и array_push. $updates[] = ... — это сокращение для добавления элементов в массив в PHP.
Теперь это новое для меня, спасибо большое, чувак
Вариант А — использовать функции SQL напрямую, как в этом вопросе/ответе: stackoverflow.com/questions/62670745/…, в противном случае это зависит от того, как часто вы это используете. Если это только один раз, то есть для «заполнения» недостающих данных, которые теперь будут добавляться при создании/обновлении записей, не беспокойтесь о производительности слишком сильно; это миграция данных в этот момент.