• Czas czytania ~3 min
  • 27.02.2023
 

Czasami trzeba odświeżyć dane w bazie danych.  Najprostszą opcją jest po prostu uruchomienie aktualizacji w bazie danych MySQL. To nie zawsze działa. Zwłaszcza, gdy korzystasz z wydarzeń lub chcesz odnowić związek ....

Polecenia

W takim przypadku zalecam utworzenie polecenia. Nawet w przypadku jednorazowych zmian.

php artisan make:command YourCommandName

Wskaźnik postępu

Pierwszą wskazówką będzie użycie paska postępu. W zespołach długoterminowych pomocne jest obserwowanie, że jest postęp.

Aby pokazać, jak po prostu kopiuję przykład z Laravel Documentation.

$users = App\Models\User::all();

$bar = $this->output->createProgressBar(count($users));

$bar->start();

foreach ($users as $user) {
    $this->performTask($user);

    $bar->advance();
}

$bar->finish();

Działa

świetnie dla nawet kilkuset wpisów z łatwymi zmianami. Jeśli chcesz zmienić więcej rekordów o większej złożoności, użyj wyników wyszukiwania.

Problem polega na tym, że jeśli prześlesz wszystko do swojej elokwentnej kolekcji, twoja jagnięcina będzie ograniczeniem. Aby tego uniknąć, można użyć wbudowanej części funkcji Laravel w zapytaniach, aby powtarzać tabelę sekwencyjnie.

App\Models\User::chunk(200, function ($users){
    foreach($users as $user){
        $user->name .= ' :)';
        $user->save();
    }
});

Jedną z ważnych rzeczy, które należy zrozumieć w przypadku funkcji urywka, jest zrozumienie sposobu wykonywania zapytań. W tym przykładzie po iteracji 200 użytkowników zapytanie podstawowe jest uruchamiane ponownie z funkcją LMIT w tabeli. 

Wyobraź sobie, że masz taki przypadek

App\Models\User::where('active', true)
    ->chunk(200, function ($users){
        foreach($users as $user){
            $user->active = false;
            $user->save();
        }
    });

W tym kodzie przekroczy 200 użytkowników, zmieniając aktywną wartość na false.  Przy drugim uruchomieniu ponownie zażąda bazy danych dla użytkowników, którzy mają aktywną prawdę. Problem polega na tym, że skoro właśnie zmieniliśmy status aktywnych 200 użytkowników, dostalibyśmy listę bez nich. Ale funkcja Limit ograniczy wynik od 200 do 400 w wynikach. Oznacza to, że przegapimy 200 użytkowników, których tak naprawdę chcieliśmy zmienić.

Laravel ma funkcję przezwyciężania problemu, ważne jest, aby zrozumieć, kiedy go użyć. Więc rozwiązanie w tej sytuacji będzie.

App\Models\User::where('active', true)
    ->chunkById(200, function ($users){
        foreach($users as $user){
            $user->active = false;
            $user->save();
        }
    });

Transakcje bazy danych

Możemy teraz wprowadzić wiele zmian w naszych modelach i unikamy problemu zbyt dużych zbiorów naszych elokwentnych. 

Ale w naszym najnowszym przykładzie wykonamy zaktualizowane oświadczenie dla każdego indywidualnego użytkownika naszej bazy danych. Aby tego uniknąć, uznałem za dobrą taktykę stosowanie transakcji. 

Dzięki temu możemy ponownie wykorzystać nasze kawałki i zaktualizować bazę danych do fragmentu.

App\Models\User::where('active', true)
    ->chunkById(200, function ($users){
        try {
            DB::beginTransaction();
            
            foreach($users as $user){
                $user->active = false;
                $user->save();
            }
           
            DB::commit();

        } catch (\Exception $e) {
            //handle your error (log ...)
            DB::rollBack();
        }
    });

W tym przykładowym kodzie łączymy chunkById z transakcjami bazy danych. Pozwala to zaoszczędzić dużo czasu na aktualizowaniu bazy danych. Więcej informacji na temat Transakcje bazy danych można znaleźć w dokumentacji Laravel.

Transakcje mogą powodować problemy, jeśli są używane nieprawidłowo. Jeśli zapomnisz wykonać lub wycofać, utworzysz zagnieżdżone transakcje. Możesz przeczytać więcej w Blogpost

Połącz to razem

Aby ukończyć ten przykładowy kod, możemy ponownie wprowadzić pasek postępu.

$count = App\Models\User::where('active', true)->count();

$bar = $this->output->createProgressBar($count);
$bar->start();

App\Models\User::where('active', true)
    ->chunkById(200, function ($users){
        try {
            DB::beginTransaction();
            
            foreach($users as $user){
                $user->active = false;
                $user->save();
                $bar->advance();
            }
           
            DB::commit();

        } catch (\Exception $e) {
            //handle your error (log ...)
            DB::rollBack();
            $bar->finish();
        }
    });

$bar->finish();

To jest moja strategia obsługi aktualizacji większych zestawów danych. Możesz zmienić rozmiar elementu zgodnie ze swoimi potrzebami i eksperymentami, co przyniesie Ci dobre efekty. Z mojego doświadczenia wynika, że coś na 200 - 1000 jest normalne.

Czasami, zwłaszcza gdy obliczenia dla pojedynczego rekordu są bardziej skomplikowane, widzę, że cały proces staje się wolniejszy po każdym przetwarzaniu. Zaczyna się od około 2 sekund na pasku, aby przejść do 30 lub 40 sekund. Ponieważ doświadczyłem tego w różnych zespołach, nie jestem pewien, czy jest to wspólny temat. Jeśli ktoś ma jakieś informacje na ten temat, daj mi znać.

Mam nadzieję, że ten artykuł ci pomoże.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297