it-swarm-eu.dev

pomalá rychlost načítání dat z mysqldump

Mám databázi MySQL střední velikosti s asi 30 tabulkami, z nichž některé jsou 10 milionů záznamů, asi 100 milionů. mysqldump všech tabulek (do samostatných souborů) je poměrně rychlý, trvá asi 20 minut. Generuje asi 15 GB dat. Největší dumpingové soubory jsou v rozsahu 2 GB.

Když načtu data do MySQL na jiném boxu, šestijádrovém, 8GB stroji, bude to trvat věčně. Snadno 12 hodin nebo více.

Právě spouštím klienta mysql pro načtení souboru, tj.

mysql database < footable.sql

přímo se souborem přímo z mysqldump

mysqldump database foo > footable.sql

Jasně dělám něco špatně. Kde mám začít, aby mohl skončit v rozumném čase?

Nepoužívám žádné přepínače na výpisu ani na zatížení.

21
Pat Farrell

Vezměte na vědomí tyto body, které vám mohou pomoci v případě vygenerování výpisu a jeho obnovení.

  1. Použijte Extended inserts na skládkách.
  2. Vypsat s --tab formát, takže můžete použít mysqlimport, která je rychlejší než mysql < dumpfile.
  3. Import s více podprocesy, jeden pro každou tabulku.
  4. Pokud je to možné, použijte jiný databázový stroj. import do silně transakčního motoru jako je innodb je hrozně pomalý. Vložení do netransakčního motoru, jako je MyISAM, je mnohem rychlejší.
  5. Vypněte kontrolu cizího klíče a zapněte automatické potvrzování.
  6. Pokud importujete pro inodb, jedinou nejúčinnější věcí, kterou můžete udělat, je dát innodb_flush_log_at_trx_commit = 2 v my.cnf, dočasně během importu. můžete jej vrátit zpět na 1, pokud potřebujete ACID

Pokusit se..

22
Abdul Manaf

V poslední době se toho hodně zabývám. Rozhodně můžete zlepšit výkon importu paralelním importem. Většina zpomalení je založena na I/O, ale stále můžete dosáhnout 40% zlepšení dumpingem do tabulek a jejich importem řeknete 4 najednou.

Můžete to udělat s xargs, jako je tento:

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

gzipování souborů před jejich přemístěním do mysql nic nezpomalí většinou kvůli sníženému I/O. Moje tabulky byly komprimovány na asi 10: 1, takže šetří spoustu místa na disku.

Zjistil jsem, že na 4 základních strojích je použití 4 procesů optimální, i když jen o něco lepší než použití 3. Pokud máte SSD nebo rychlý RAID, budete pravděpodobně lépe škálovat.

Některé další věci na vědomí. Pokud máte 4k sektorové jednotky, ujistěte se, že máte key_cache_block_size=4096 a myisam_block_size=4K.

Pokud používáte tabulky MyISAM, nastavte myisam_repair_threads = 2 nebo vyšší. To umožní vašim dalším jádrům pomoci znovu vytvořit indexy.

Ujistěte se, že nevyměňujete vůbec. Pokud ano, zmenšete velikost innodb_buffer_pool_size.

Myslím, že jsem dostal nějaké urychlení s innnodb také těmito možnostmi:

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(Poslední tři jsem rozsáhle netestoval - myslím, že jsem je našel jako návrhy na internetu.) Všimněte si, že innodb_flush_log_at_commit=0 může vést k poškození s pádem mysql nebo výpadkem napájení.

7
greg

Kromě odpovědi Abdul bych rád zdůraznil význam --disable-keys volba, která vypíná klíče, dokud nejsou všechna data načtena do tabulky. Tato volba je povolena jako součást --opt přepínač, který je ve výchozím nastavení povolen, ale domníval se, že je důležité zdůraznit.

Pokud během vložení nevynecháte klíče, každý vložený řádek znovu vytvoří index. Extrémně pomalý proces.

7
Derek Downey

Pokud máte hlavně tabulky MyISAM, měli byste zvýšit buffer pro hromadné vkládání . Zde je to, co MySQL dokumentace říká o nastavení bulk_insert_buffer_size :

MyISAM používá speciální stromovou mezipaměť, aby zrychlil hromadné vkládání INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., a LOAD DATA INFILE při přidávání dat do neprázdných tabulky. Tato proměnná omezuje velikost stromu mezipaměti v bajtech na vlákno. Nastavení na 0 zakáže tuto optimalizaci. Výchozí hodnota je 8 MB.

Musíte udělat dvě věci

1) Přidejte ji do souboru /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Nastavte globální hodnotu

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Pokud nemáte oprávnění globálně nastavit hromadné vložení_obsahu, pak to udělejte

service mysql restart

To samozřejmě není pro InnoDB.

Z jiného úhlu, ať už jsou tabulky InnoDB nebo MyISAM, pokud jsou indexy větší než tabulka, můžete mít příliš mnoho indexů. Obvykle jsem hostit, že opakované načtení MyISAM mysqldumpu by mělo trvat 3krát, dokud to mysqldump trvalo. Také si myslím, že opětovné načtení InnoDB mysqldumpu by mělo trvat 4krát, dokud to mysqldump trvalo.

Pokud překročíte poměr 4: 1 pro načtení mysqldumpu, určitě máte jeden ze dvou problémů:

  • příliš mnoho indexů
  • indexy prostě příliš velké kvůli velkým sloupcům

Velikost paměti můžete změřit pomocí paměťového modulu s tímto:

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

Zjistěte, zda jsou indexy téměř stejně velké jako data nebo dokonce větší

Můžete také zvážit zakázání binárního protokolování takto:

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

před načtením skriptu

5
RolandoMySQLDBA

Pokud zcela obejdete souborový systém a pouze přenesete výstup mysqldump přímo do procesu MySQL, měli byste vidět nápadná zlepšení výkonu. Kolik nakonec závisí na typu diskové jednotky, kterou používáte, ale zřídka používám soubory výpisu bez ohledu na velikost databáze pouze z tohoto důvodu.

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy
2
Marcus Pope

Podle mých zkušeností je pevný disk problémovým místem. Zapomeňte na rotující disky. SSD je lepší, ale zdaleka nejlepší je provést to v RAM - - pokud máte dost držet celou databázi na krátkou dobu. Zhruba:

  1. zastavte mysqld
  2. přesunout existující obsah/var/lib/mysql
  3. vytvořte prázdný adresář/var/lib/mysql
  4. mount -t tmpfs -o size = 32g tmpfs/var/lib/mysql (upravit velikost)
  5. vytvořit prázdný db (např. mysql_install_db, nebo obnovit předchozí obsah)
  6. začít mysqld
  7. import
  8. zastavte mysqld
  9. zkopírujte/var/lib/mysql do mysql2
  10. umount mysql; rmdir mysql
  11. přesuňte mysql2 na mysql
  12. začni mysqld, buď šťastný

Pro mě lze skládku ~ 10G (/ var/lib/mysql náročné ~ 20G) importovat za přibližně 35 minut (mydumper/myloader), 45 minut (mysqldump - tab/mysqlimport), 50 minut (mysqldump/mysql) , na 2x6jádrovém 3,2 GHz Xeon.

Pokud nemáte dostatek RAM v jednom počítači, ale máte několik počítačů vedle sebe s rychlou sítí, bylo by zajímavé zjistit, zda jejich RAM lze spojit s nbd (síť blokové zařízení) Nebo s innodb_file_per_table můžete pravděpodobně výše uvedený proces zopakovat pro každou tabulku.

1
egmont