개별 데이터로 여러 레코드 대량 업데이트 — Laravel
"데이터베이스 트랜잭션"은 비용이 많이 드는 작업입니다.
예를 들어 인벤토리 소프트웨어를 설계했고 1년 동안 생산에 사용했으며 1,000,000건의 거래에 도달했다고 가정해 보겠습니다.
갑자기 우리는 거래에 VAT를 추가하지 않았다는 것을 알게 되었습니다. 미래의 거래에 대해서는 다루기가 매우 쉽습니다. 아마도 돌연변이원일 수도 있습니다.
class Transaction extends Model {
public $vat = 0.20;
public function setPriceAttribute($value) {
$this->attributes['price'] += $value * $this->vat;
}
}
미래의 기록은 다루기가 매우 쉽습니다. 그러나 과거의 100만 레코드를 어떻게 편집할 것입니까?
과거의 데이터를 편집하려면 Seeder를 만드는 것을 선호합니다.
php artisan make:seeder AddVatToTransactions
어떻게하지?
class AddVatToTransactions extends Seeder {
public function run()
{
$vat = 0.20;
$transactions = Transaction::get();
foreach ($transactions as $transaction) {
$transaction->price += $transaction->price * $vat
$transaction->save();
}
}
}
그러나 100만 개의 루프에서 실행하고 루프의 각 반복에서 "데이터베이스 트랜잭션"을 만드는 것은 좋은 생각이 아닙니다! (스포일러 경고: 시스템이 정지됩니다 😀)
그렇다면 어떻게 해야 할까요?
다시, 우리의
AddVatToTransactions
시더에서:mysql 쿼리의 아이디어는 "CASE 문"입니다.
UPDATE db.transactions
SET PRICE = CASE
WHEN id = 3 THEN 500
WHEN id = 4 THEN 300
END
WHERE ID IN (3, 4)
이제 Laravel에서 해봅시다.
$vat = 0.20;
$transactions = Transaction::get();
$cases = [];
$ids = [];
$params = [];
foreach ($transactions as $transaction) {
$cases[] = "WHEN {$transaction->id} then ?";
$params[] = $transaction->profit * $vat;
$ids[] = $transaction->id;
}
$ids = implode(',', $ids);
$cases = implode(' ', $cases);
if (!empty($ids)) {
\DB::update("UPDATE transactions SET `price` = CASE `id` {$cases} END WHERE `id` in ({$ids})", $params);
}
이것은 하나의 데이터베이스 트랜잭션을 만들어 모든 업데이트를 작성합니다.⚡️
🗣 "아직도 얼고 있어"라는 말을 들을 수 있습니다.
그래서.. 더 최적화:
#1: RAM을 덜 사용하기 위해 데이터베이스에서 필요한 데이터만 "선택"하십시오.
이 예에서는 "id"및 "price"열만 사용합니다. 그래서 그것들 만 선택합시다.
$transactions = Transaction::select('id', 'price')->get();
#2: 컬렉션을 "청크"하여 트랜잭션을 여러 데이터베이스 트랜잭션으로 분리합니다.
Laravel에서는 다음과 같은 청크 컬렉션을 만들 수 있습니다.
Transaction::get()->chunk(5000);
예제에 모두 적용해 보겠습니다.
여기에서 먼저
$transactions
컬렉션을 5000개의 청크로 나누고 한 번에 5k 레코드당 "데이터베이스 트랜잭션"을 수행합니다.$vat = 0.20;
$transactions = Transaction::get();
foreach ($transactions->chunk(5000) as $chunk) {
$cases = [];
$ids = [];
$params = [];
foreach ($chunk as $transaction) {
$cases[] = "WHEN {$transaction->id} then ?";
$params[] = $transaction->profit * $vat;
$ids[] = $transaction->id;
}
$ids = implode(',', $ids);
$cases = implode(' ', $cases);
if (!empty($ids)) {
\DB::update("UPDATE transactions SET `price` = CASE `id` {$cases} END WHERE `id` in ({$ids})", $params);
}
}
이 트릭이 마음에 드셨으면 좋겠습니다!
댓글로 여러분의 생각을 알려주세요 💬
즐거운 코딩하세요! 😊
Reference
이 문제에 관하여(개별 데이터로 여러 레코드 대량 업데이트 — Laravel), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/kodeas/bulk-update-multiple-records-with-separate-data-laravel-4j7k텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)