Jakékoli INSERT ... SELECT ...
dotaz získává SHARED zámek
na řádcích, které čte ze zdrojové tabulky v SELECT. Ale zpracováním menších kusů řádků zámek nevydrží příliš dlouho.
Dotaz s LIMIT ... OFFSET
bude pomalejší a pomalejší, jak budete postupovat zdrojovou tabulkou. Při 10 000 řádcích na blok musíte tento dotaz spustit 10 000krát, každý z nich musí začít znovu a prohledat tabulku, abyste dosáhli nového OFFSET.
Bez ohledu na to, co děláte, kopírování 100 milionů řádků bude chvíli trvat. Dělá to hodně práce.
Použil bych pt-archiver , bezplatný nástroj určený pro tento účel. Zpracovává řádky v „kusech“ (nebo podmnožinách). Dynamicky upraví velikost bloků tak, aby každý blok trval 0,5 sekundy.
Největší rozdíl mezi vaší metodou a pt-archiverem je ten, že pt-archiver nepoužívá LIMIT ... OFFSET
, prochází indexem primárního klíče a vybírá části řádku podle hodnoty místo podle pozice. Každý blok se tedy čte efektivněji.
K vašemu komentáři:
Očekávám, že zmenšením velikosti dávky – a zvýšením počtu iterací – se problém s výkonem zhorší , ne lepší.
Důvodem je, že když použijete LIMIT
s OFFSET
, každý dotaz musí začínat znovu na začátku tabulky a počítat řádky až do OFFSET
hodnota. To se prodlužuje a prodlužuje, jak budete iterovat tabulkou.
Spuštění 20 000 drahých dotazů pomocí OFFSET
bude trvat déle než spuštění 10 000 podobných dotazů. Nejdražší částí nebude čtení 5 000 nebo 10 000 řádků, ani jejich vkládání do cílové tabulky. Drahá část bude přeskakovat ~50 000 000 řádků, znovu a znovu.
Místo toho byste měli iterovat tabulku podle hodnot ne pomocí offsetů.
INSERT IGNORE INTO Table2(id, field2, field3)
SELECT f1, f2, f3
FROM Table1
WHERE id BETWEEN rowOffset AND rowOffset+limitSize;
Před smyčkou zadejte MIN(id) a MAX(id) a spusťte rowOffset
na minimální hodnotu a smyčku až na maximální hodnotu.
Takto funguje pt-archiver.