Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wstawianie MySql do zapytania select jest zbyt wolne, aby skopiować 100 milionów wierszy

Dowolny INSERT ... SELECT ... zapytanie uzyska blokadę SHARED w wierszach, które odczytuje z tabeli źródłowej w SELECT. Ale przetwarzając mniejsze fragmenty wierszy, blokada nie trwa zbyt długo.

Zapytanie z LIMIT ... OFFSET będzie wolniej i wolniej w miarę przechodzenia przez tabelę źródłową. Przy 10 000 wierszy na porcję, musisz uruchomić to zapytanie 10 000 razy, każde z nich musi zacząć od nowa i przeskanować tabelę, aby osiągnąć nowe PRZESUNIĘCIE.

Bez względu na to, co zrobisz, skopiowanie 100 milionów wierszy zajmie trochę czasu. Robi dużo pracy.

Używałbym pt-archiver , darmowe narzędzie przeznaczone do tego celu. Przetwarza wiersze w „kawałkach” (lub podzbiorach). Dynamicznie dostosuje rozmiar porcji, tak aby każda porcja trwała 0,5 sekundy.

Największą różnicą między twoją metodą a pt-archiver jest to, że pt-archiver nie używa LIMIT ... OFFSET , przechodzi wzdłuż indeksu klucza podstawowego, wybierając fragmenty wiersza według wartości zamiast według pozycji. Dzięki temu każdy fragment jest czytany wydajniej.

Odpowiedz na swój komentarz:

Spodziewam się, że zmniejszenie rozmiaru partii — i zwiększenie liczby iteracji — spowoduje, że problem z wydajnością pogorszy się , nie lepiej.

Powodem jest to, że gdy używasz LIMIT z OFFSET , każde zapytanie musi zaczynać się od początku tabeli i liczyć wiersze aż do OFFSET wartość. To staje się coraz dłuższe, gdy przechodzisz przez tabelę.

Uruchamianie 20 000 kosztownych zapytań przy użyciu OFFSET zajmie więcej czasu niż uruchomienie 10 000 podobnych zapytań. Najdroższą częścią nie będzie odczytywanie 5 000 lub 10 000 wierszy ani wstawianie ich do tabeli docelowej. Kosztowna część będzie przeskakiwać przez ~50 000 000 wierszy w kółko.

Zamiast tego powinieneś iterować po tabeli według wartości nie przez przesunięcia.

INSERT IGNORE INTO Table2(id, field2, field3)
        SELECT f1, f2, f3
        FROM Table1
        WHERE id BETWEEN rowOffset AND rowOffset+limitSize;

Przed pętlą zapytaj o MIN(id) i MAX(id) i uruchom rowOffset przy minimalnej wartości i zapętlaj do maksymalnej wartości.

Tak działa pt-archiver.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Problemy z Mysql Query przy użyciu LIKE i apostrofu

  2. SQL Insert Row i skopiuj wstawiony identyfikator Auto-Increment do innej kolumny

  3. Wstaw do wyboru i zaktualizuj w jednym zapytaniu

  4. Jakie są największe korzyści z używania INDEKSÓW w mysql?

  5. Jak mogę włączyć logowanie wolnych zapytań MySQL na moim serwerze?