sql >> Database teknologi >  >> RDS >> Mysql

MySql-indsættelse i udvalgt forespørgsel er for langsom til at kopiere 100 millioner rækker

Enhver INSERT ... SELECT ... forespørgsel skaffer en DELT lås på rækkerne den læser fra kildetabellen i SELECT. Men ved at behandle mindre bidder af rækker holder låsen ikke for længe.

Forespørgslen med LIMIT ... OFFSET vil være langsommere og langsommere, efterhånden som du går gennem kildetabellen. Ved 10.000 rækker pr. chunk skal du køre den forespørgsel 10.000 gange, hver enkelt skal starte forfra og scanne gennem tabellen for at nå den nye OFFSET.

Uanset hvad du gør, vil kopiering af 100 millioner rækker tage et stykke tid. Det gør en masse arbejde.

Jeg ville bruge pt-archiver , et gratis værktøj designet til dette formål. Den behandler rækkerne i "bidder" (eller delmængder). Det vil dynamisk justere størrelsen af ​​bidderne, så hver chunk tager 0,5 sekunder.

Den største forskel mellem din metode og pt-archiver er, at pt-archiver ikke bruger LIMIT ... OFFSET , går den langs det primære nøgleindeks og vælger bidder af række efter værdi i stedet for efter position. Så hver del læses mere effektivt.

Om din kommentar:

Jeg forventer, at at gøre batchstørrelsen mindre – og øge antallet af iterationer – vil gøre ydeevneproblemet værre , ikke bedre.

Årsagen er, at når du bruger LIMIT med OFFSET , hver forespørgsel skal starte forfra ved begyndelsen af ​​tabellen og tælle rækkerne op til OFFSET værdi. Dette bliver længere og længere, efterhånden som du gentager bordet.

Kører 20.000 dyre forespørgsler ved hjælp af OFFSET vil tage længere tid end at køre 10.000 lignende forespørgsler. Den dyreste del vil ikke være at læse 5.000 eller 10.000 rækker eller indsætte dem i destinationstabellen. Den dyre del vil være at springe gennem ~50.000.000 rækker igen og igen.

I stedet bør du iterere over tabellen efter værdier ikke ved forskydninger.

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

Før løkken, forespørg MIN(id) og MAX(id), og start rowOffset ved min-værdien, og sløjfe op til max-værdien.

Dette er måden pt-archiver fungerer på.



  1. Søgning efter tekst i Oracle Stored Procedures

  2. Django / MySQL:Hvordan laver man autonome transaktioner (forpligter kun undersæt af forespørgsler)?

  3. MySQL Integer vs DateTime indeks

  4. Hvordan bygger man et simpelt anmeldelses- og 5-stjernet ratingsystem?