sql >> Databáze >  >> RDS >> Mysql

Vložení MySql do výběrového dotazu je příliš pomalé na zkopírování 100 milionů řádků

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.



  1. SQL - Jak najít nejvyšší číslo ve sloupci?

  2. MySQL LOAD DATA INFILE s čárkou jako oddělovačem desetinných míst

  3. Chyba aktualizace záznamu Vb6

  4. Jak odstranit duplikáty ze seznamu odděleného čárkami pomocí regexp_replace v Oracle?