sql >> Databasteknik >  >> RDS >> Mysql

MySql-infogningen i den valda frågan är för långsam för att kopiera 100 miljoner rader

Valfri INSERT ... SELECT ... skaffar frågan ett DELAT lås på raderna läses den från källtabellen i SELECT. Men genom att bearbeta mindre bitar av rader varar låset inte för länge.

Frågan med LIMIT ... OFFSET kommer att bli långsammare och långsammare när du går igenom källtabellen. Vid 10 000 rader per bit måste du köra den frågan 10 000 gånger, var och en måste börja om och skanna igenom tabellen för att nå den nya OFFSET.

Oavsett vad du gör kommer det att ta ett tag att kopiera 100 miljoner rader. Den gör mycket jobb.

Jag skulle använda pt-archiver , ett gratis verktyg designat för detta ändamål. Den bearbetar raderna i "bitar" (eller delmängder). Det kommer dynamiskt att justera storleken på bitarna så att varje bit tar 0,5 sekunder.

Den största skillnaden mellan din metod och pt-archiver är att pt-archiver inte använder LIMIT ... OFFSET , går den längs det primära nyckelindexet och väljer bitar av rad efter värde istället för efter position. Så varje bit läses mer effektivt.

Angående din kommentar:

Jag förväntar mig att att göra satsstorleken mindre – och öka antalet iterationer – kommer att göra prestandaproblemet värre , inte bättre.

Anledningen är att när du använder LIMIT med OFFSET , varje fråga måste börja om i början av tabellen och räkna raderna upp till OFFSET värde. Detta blir längre och längre när du itererar genom tabellen.

Kör 20 000 dyra frågor med OFFSET kommer att ta längre tid än att köra 10 000 liknande frågor. Den dyraste delen kommer inte att vara att läsa 5 000 eller 10 000 rader, eller infoga dem i destinationstabellen. Den dyra delen kommer att hoppa över ~50 000 000 rader, om och om igen.

Istället bör du iterera över tabellen med värden inte genom förskjutningar.

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

Före loopen, fråga MIN(id) och MAX(id) och starta rowOffset vid min-värdet och loop upp till maxvärdet.

Det är så pt-archiver fungerar.



  1. Att hämta data från RDS ger AttributeError:'sqlalchemy.cimmutabledict.immutabledict'-objektet har inget attribut 'setdefault'

  2. Postgres och index på främmande nycklar och primärnycklar

  3. hur släpper man partition utan att tappa data i MySQL?

  4. Mysql SKAPA DEFINER