it-swarm.it

velocità di caricamento lenta dei dati da mysqldump

Ho un database MySQL di dimensioni moderate con circa 30 tabelle, alcune delle quali sono 10 milioni di record, circa 100 milioni. Il mysqldump di tutte le tabelle (in file separati) è abbastanza veloce, impiega forse 20 minuti. Genera circa 15 GB di dati. I più grandi file scaricati sono nella gamma di 2 GB.

Quando carico i dati in MySQL su un'altra scatola, una macchina a sei core da 8 GB, ci vuole sempre. Facilmente 12 ore o più.

Sto solo eseguendo il client mysql per caricare il file, ad es.

mysql database < footable.sql

direttamente con il file direttamente da mysqldump

mysqldump database foo > footable.sql

Chiaramente sto facendo qualcosa di sbagliato. Da dove comincio in modo che possa finire in un tempo ragionevole?

Non sto usando alcun interruttore né sul dump né sul carico.

21
Pat Farrell

Prendi in considerazione questi punti che potrebbero aiutarti in caso di generazione del dump e ripristino.

  1. Uso Extended inserts in discarica.
  2. Dump con --tab in modo da poter utilizzare mysqlimport, che è più veloce di mysql < dumpfile.
  3. Importa con più thread, uno per ogni tabella.
  4. Utilizzare un motore di database diverso, se possibile. l'importazione in un motore fortemente transazionale come innodb è terribilmente lenta. L'inserimento in un motore non transazionale come MyISAM è molto più veloce.
  5. Disattiva i controlli delle chiavi esterne e attiva il commit automatico.
  6. Se stai importando su innodb l'unica cosa più efficace che puoi fare è mettere innodb_flush_log_at_trx_commit = 2 nel tuo my.cnf, temporaneamente mentre l'importazione è in esecuzione. puoi rimetterlo a 1 se hai bisogno di ACID

Provaci..

22
Abdul Manaf

Ho avuto a che fare molto con questo ultimamente. Puoi sicuramente migliorare le prestazioni delle importazioni eseguendo le importazioni in parallelo. La maggior parte del rallentamento si basa sull'I/O, ma è comunque possibile ottenere un miglioramento del 40% scaricando le tabelle e quindi importandole 4 alla volta.

Puoi farlo con xargs come questo:

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

avere i file compressi con i gzip prima di inviarli a mysql non rallenta nulla principalmente a causa dell'I/O abbassato. I miei tavoli sono stati compressi fino a circa 10: 1, quindi consente di risparmiare molto spazio su disco.

Ho scoperto che su 4 macchine core, l'utilizzo di 4 processi è ottimale, sebbene solo leggermente migliore dell'uso 3. Se si dispone di SSD o RAID veloce, è probabile che si ridimensioni meglio.

Alcune altre cose da notare. Se hai unità settoriali 4k, assicurati di avere key_cache_block_size=4096 e myisam_block_size=4K.

Se stai utilizzando le tabelle MyISAM, imposta myisam_repair_threads = 2 o più alto. Ciò consentirà ai tuoi core extra di aiutarti a ricostruire gli indici.

Assicurati di non scambiare affatto. Se lo sei, riduci le dimensioni di innodb_buffer_pool_size.

Penso di aver ottenuto un po 'di accelerazione con innnodb anche da queste opzioni:

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

(gli ultimi tre non ho testato ampiamente - penso di averli trovati come suggerimenti su Internet.) Nota che il innodb_flush_log_at_commit=0 può provocare la corruzione in caso di arresto anomalo di mysql o interruzione dell'alimentazione.

7
greg

Oltre alla risposta Abdul's , vorrei sottolineare l'importanza della --disable-keys opzione, che disattiva le chiavi fino a quando tutti i dati non vengono caricati per una tabella. Questa opzione è abilitata come parte di --opt attiva/disattiva, che è abilitato per impostazione predefinita, ma che è importante sottolineare.

Se non si saltano le chiavi durante gli inserimenti, ogni riga inserita ricostruirà l'indice. Un processo estremamente lento.

7
Derek Downey

Se disponi principalmente di tabelle MyISAM, dovresti aumentare bulk insert buffer . Ecco cosa dice la documentazione di MySQL sull'impostazione bulk_insert_buffer_size :

MyISAM utilizza una speciale cache ad albero per rendere più rapidi gli inserimenti di massa per INSERT ... SELECT, INSERT ... VALUES (...), (...), ... e LOAD DATA INFILE quando si aggiungono dati a non vuoto tabelle. Questa variabile limita la dimensione dell'albero della cache in byte per thread. Impostandolo su 0 disabilita questa ottimizzazione. Il valore predefinito è 8 MB.

Ci sono due cose che devi fare

1) Aggiungilo a /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Impostare il valore globale per esso

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Se non si dispone del privilegio di impostare bulk_insert_buffer_size a livello globale, procedere come segue

service mysql restart

Naturalmente, questo non è per InnoDB.

Da un altro punto di vista, che le tabelle siano InnoDB o MyISAM, se gli indici sono più grandi di quelli della tabella, è possibile che vi siano troppi indici. Di solito mi rendo conto che un ricaricamento di un mysqldump MyISAM dovrebbe impiegare 3 volte il tempo necessario al mysqldump. Ho anche notato che un ricaricamento di un mysqldump di InnoDB dovrebbe richiedere 4 volte il tempo necessario per il mysqldump.

Se stai superando il rapporto 4: 1 per ricaricare un mysqldump, hai sicuramente uno dei due problemi:

  • troppi indici
  • indici troppo grandi a causa di colonne di grandi dimensioni

Puoi misurare la dimensione dei tuoi dati dal motore di archiviazione con questo:

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;

Verifica se gli indici sono quasi grandi quanto i dati o addirittura più grandi

Puoi anche considerare di disabilitare la registrazione binaria in questo modo:

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

prima di ricaricare lo script

5
RolandoMySQLDBA

Se si ignora del tutto il filesystem e si esegue semplicemente il pipe dell'output di mysqldump direttamente in un processo MySQL, si dovrebbero notare notevoli miglioramenti delle prestazioni. Quanto dipende in ultima analisi dal tipo di unità disco che si sta utilizzando, ma raramente utilizzo più i file di dump indipendentemente dalle dimensioni del database solo per questo motivo.

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

Secondo le mie esperienze, il disco rigido è il collo di bottiglia. Dimentica i dischi rotanti. SSD è migliore, ma di gran lunga il migliore è eseguirlo in RAM - se hai abbastanza per contenere l'intero database per un breve periodo.

  1. basta mysqld
  2. sposta i contenuti esistenti di/var/lib/mysql
  3. crea una directory vuota/var/lib/mysql
  4. mount -t tmpfs -o size = 32g tmpfs/var/lib/mysql (regola le dimensioni)
  5. creare un db vuoto (ad es. mysql_install_db o ripristinare i contenuti precedenti)
  6. avvia mysqld
  7. importare
  8. basta mysqld
  9. copia/var/lib/mysql in mysql2
  10. umount mysql; rmdir mysql
  11. sposta mysql2 in mysql
  12. avvia mysqld, sii felice

Per me, un dump di ~ 10G (/ var/lib/mysql che consuma ~ 20G) può essere importato in circa 35 minuti (mydumper/myloader), 45 minuti (mysqldump --tab/mysqlimport), 50 minuti (mysqldump/mysql) , su un Xeon da 3,2 GHz a 2x6 core.

Se non hai abbastanza RAM in una singola macchina, ma hai diversi computer uno accanto all'altro con una rete veloce, sarebbe interessante vedere se le loro RAM possono essere unite con nbd (rete blocco dispositivo) Oppure, con innodb_file_per_table, puoi probabilmente ripetere la procedura sopra descritta per ogni tabella.

1
egmont