sql >> Database >  >> RDS >> Mysql

MySql invoegen in selectiequery is te traag om 100 miljoen rijen te kopiëren

Elke INSERT ... SELECT ... query doet een SHARED lock op de rijen die het leest uit de brontabel in de SELECT. Maar door kleinere stukken rijen te verwerken, duurt het slot niet al te lang.

De zoekopdracht met LIMIT ... OFFSET zal langzamer en langzamer gaan naarmate je verder komt in de brontabel. Met 10.000 rijen per chunk moet je die query 10.000 keer uitvoeren, elke rij moet opnieuw beginnen en door de tabel bladeren om de nieuwe OFFSET te bereiken.

Wat je ook doet, het kopiëren van 100 miljoen rijen duurt even. Het doet veel werk.

Ik zou pt-archiver gebruiken , een gratis tool die voor dit doel is ontworpen. Het verwerkt de rijen in "chunks" (of subsets). Het zal de grootte van de chunks dynamisch aanpassen, zodat elke chunk 0,5 seconde duurt.

Het grootste verschil tussen uw methode en pt-archiver is dat pt-archiver geen gebruik maakt van LIMIT ... OFFSET , het loopt langs de primaire sleutelindex en selecteert stukjes rij op waarde in plaats van op positie. Zo wordt elk stuk efficiënter gelezen.

Opnieuw uw opmerking:

Ik verwacht dat het kleiner maken van de batchgrootte — en het vergroten van het aantal iteraties — het prestatieprobleem erger zal maken , niet beter.

De reden is dat wanneer u LIMIT . gebruikt met OFFSET , moet elke query opnieuw beginnen aan het begin van de tabel en de rijen tellen tot aan de OFFSET waarde. Dit wordt langer en langer naarmate je de tabel doorloopt.

20.000 dure zoekopdrachten uitvoeren met OFFSET duurt langer dan het uitvoeren van 10.000 vergelijkbare zoekopdrachten. Het duurste deel is niet het lezen van 5.000 of 10.000 rijen of het invoegen ervan in de doeltabel. Het dure deel is het overslaan van ~ 50.000.000 rijen, keer op keer.

In plaats daarvan moet u de tabel herhalen met waarden niet door offsets.

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

Vraag vóór de lus de MIN(id) en MAX(id) op en start rowOffset op de min-waarde, en loop omhoog naar de max-waarde.

Dit is de manier waarop pt-archiver werkt.



  1. Negatieve limiet offset in mysql

  2. Formuliergegevens invoegen in twee verschillende tabellen in de database via jsp-pagina

  3. Hoe automatisch een unieke id in SQL genereren, zoals UID12345678?

  4. Laravel wijzigt databaseparameters tijdens runtime