kecepatan memuat data yang lambat dari mysqldump

21

Saya punya basis data MySQL ukuran sedang dengan sekitar 30 tabel, beberapa di antaranya adalah 10 juta catatan, sekitar 100 juta. The mysqldumpsemua tabel (dalam berkas terpisah) cukup cepat, membutuhkan waktu mungkin 20 menit. Ini menghasilkan sekitar 15GB data. File yang dibuang terbesar berada dalam kisaran 2GB.

Ketika saya memuat data ke dalam MySQL di kotak lain, mesin enam-inti, 8GB, dibutuhkan selamanya. Mudah 12 jam jam atau lebih.

Saya hanya menjalankan klien mysql untuk memuat file, yaitu

mysql database < footable.sql

langsung dengan file langsung keluar dari mysqldump

mysqldump database foo > footable.sql

Jelas saya melakukan sesuatu yang salah. Di mana saya memulai sehingga bisa selesai dalam waktu yang wajar?

Saya tidak menggunakan tombol apa pun pada dump atau beban.

Pat Farrell
sumber
Anda juga dapat menonaktifkan logging biner selama pemuatan dump Anda
Cédric PEINTRE

Jawaban:

22

Ambil beberapa poin ini dalam pertimbangan Anda, mereka dapat membantu Anda dalam hal menghasilkan dump dan mengembalikannya.

  1. Gunakan Extended insertsdi tempat pembuangan.
  2. Buang dengan --tabformat sehingga Anda dapat menggunakan mysqlimport, yang lebih cepat dari mysql < dumpfile.
  3. Impor dengan beberapa utas, satu untuk setiap tabel.
  4. Gunakan mesin database yang berbeda jika memungkinkan. mengimpor ke mesin yang sangat transaksional seperti innodb sangat lambat. Memasukkan ke mesin non-transaksional seperti MyISAM jauh lebih cepat.
  5. Matikan cek kunci asing dan aktifkan komit otomatis.
  6. Jika Anda mengimpor ke innodb, satu-satunya hal paling efektif yang dapat Anda lakukan adalah memasukkan innodb_flush_log_at_trx_commit = 2my.cnf Anda, untuk sementara saat impor berjalan. Anda dapat mengembalikannya ke 1 jika Anda memerlukan ASAM

Cobalah..

Abdul Manaf
sumber
Petunjuk Anda dengan innodb_flush_log_at_trx_commit = 2menyelamatkan hari saya. Mengimpor dump 600 MB (sebagai transaksi besar tunggal) akan membutuhkan 6 jam, tetapi dengan pengaturan sementara ini, itu dilakukan dalam 30 menit!
Daniel Marschall
1
Hal-hal yang Anda harap Anda ketahui sebelum mencoba memuat basis data 80gig dari dump 4 hari setelah menekan 'enter' ... :)
Dmitri DB
7

Selain jawaban Abdul , saya ingin menekankan pentingnya --disable-keysopsi, yang mematikan kunci sampai semua data dimuat untuk sebuah tabel. Opsi ini diaktifkan sebagai bagian dari --optsakelar, yang diaktifkan secara default, tetapi menganggapnya penting untuk ditunjukkan.

Jika Anda tidak melewatkan kunci selama sisipan, maka setiap baris yang dimasukkan akan membangun kembali indeks. Proses yang sangat lambat.

Derek Downey
sumber
Apakah --disable-keys bagian dari mysqldump? atau memuat ulang?
Pat Farrell
itu akan ditambahkan dalam file dump
Derek Downey
--optdiaktifkan secara default
jberryman
1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Ethan Allen
7

Saya telah banyak berurusan dengan ini belakangan ini. Anda pasti dapat meningkatkan kinerja impor dengan melakukan impor secara paralel. Sebagian besar perlambatan berbasis I / O, tetapi Anda masih bisa mendapatkan peningkatan 40% dengan membuang ke dalam tabel dan kemudian mengimpornya mengatakan 4 pada suatu waktu.

Anda dapat melakukan ini dengan xargs seperti ini:

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

memiliki file yang di-gzip sebelum mendorongnya ke mysql tidak memperlambat apa pun terutama karena I / O yang diturunkan. Meja saya dikompresi hingga sekitar 10: 1, sehingga menghemat banyak ruang disk.

Saya telah menemukan bahwa pada mesin 4 inti, menggunakan 4 proses adalah optimal, meskipun hanya sedikit lebih baik daripada menggunakan 3. Jika Anda memiliki SSD atau RAID cepat, Anda mungkin akan skala yang lebih baik.

Beberapa hal lain yang perlu diperhatikan. Jika Anda memiliki drive sektor 4k, pastikan Anda memilikinyakey_cache_block_size=4096 dan myisam_block_size=4K.

Jika Anda menggunakan tabel MyISAM, atur tabel myisam_repair_threads = 2 atau lebih tinggi. Ini akan memungkinkan core tambahan Anda untuk membantu membangun kembali indeks.

Pastikan Anda tidak bertukar sama sekali. Jika ya, kurangi ukuraninnodb_buffer_pool_size .

Saya pikir saya mendapat beberapa speedup dengan innnodb dengan opsi ini juga:

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

(tiga terakhir saya tidak menguji secara luas - saya pikir saya menemukan mereka sebagai saran di internet.) Perhatikan bahwa innodb_flush_log_at_commit=0dapat mengakibatkan korupsi dengan mysql crash atau daya padam.

greg
sumber
Greg, selamat datang di situs dan terima kasih atas jawaban Anda. Bisakah Anda memberikan beberapa sumber atau alasan untuk saran Anda *_block_sizedan myisam_repair_threads? Juga, tidak yakin kami harus menawarkan saran untuk menyetel variabel berdasarkan 'saran dari internet' :)
Derek Downey
5

Jika Anda terutama memiliki tabel MyISAM, Anda harus menambah buffer sisipan massal . Inilah yang dikatakan Dokumentasi MySQL tentang pengaturan bulk_insert_buffer_size :

MyISAM menggunakan cache mirip pohon untuk membuat sisipan massal lebih cepat untuk INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., dan LOAD DATA INFILE saat menambahkan data ke nonempty meja. Variabel ini membatasi ukuran pohon cache dalam byte per utas. Menetapkannya ke 0 menonaktifkan pengoptimalan ini. Nilai default adalah 8MB.

Ada dua hal yang perlu Anda lakukan

1) Tambahkan ke /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Tetapkan nilai global untuk itu

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Jika Anda tidak memiliki hak istimewa untuk mengatur bulk_insert_buffer_size secara global, maka lakukan ini

service mysql restart

Tentu saja, ini bukan untuk InnoDB.

Dari sudut lain, apakah tabelnya InnoDB atau MyISAM, jika indeks lebih besar dari tabel, Anda mungkin memiliki terlalu banyak indeks. Saya biasanya merasa bahwa pemuatan ulang myISAM mysqldump akan memakan waktu 3 kali selama mysqldump diperlukan. Saya juga memberi tahu bahwa memuat ulang mysqldump InnoDB harus memakan waktu 4 kali lipat selama mysqldump dibuat.

Jika Anda melebihi rasio 4: 1 untuk memuat ulang mysqldump, Anda pasti memiliki satu dari dua masalah:

  • indeks terlalu banyak
  • indeks terlalu besar karena kolom besar

Anda dapat mengukur ukuran data Anda dengan mesin penyimpanan dengan ini:

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;

Lihat apakah indeks hampir sebesar data atau bahkan lebih besar

Anda juga dapat mempertimbangkan menonaktifkan pencatatan biner seperti ini:

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

sebelum memuat ulang skrip

RolandoMySQLDBA
sumber
Saya tidak tahu berapa kali Anda menyelamatkan hari saya, tetapi itu pasti banyak
Dmitri DB
2

Jika Anda mem-bypass sistem file sama sekali dan hanya menyalurkan output mysqldump langsung ke proses MySQL, Anda akan melihat peningkatan kinerja yang nyata. Seberapa besar akhirnya tergantung pada jenis disk drive yang Anda gunakan, tetapi saya jarang menggunakan file dump lagi terlepas dari ukuran database karena alasan ini saja.

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

Menurut pengalaman saya, hard drive adalah hambatannya. Lupakan disk yang berputar. SSD lebih baik, tetapi sejauh ini yang terbaik adalah melakukan ini dalam RAM - jika Anda memiliki cukup untuk menahan seluruh database untuk sementara waktu. Kurang lebih:

  1. hentikan mysqld
  2. memindahkan isi / var / lib / mysql yang sudah ada
  3. buat direktori kosong / var / lib / mysql
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql (sesuaikan ukurannya)
  5. buat db kosong (mis. mysql_install_db, atau pulihkan konten sebelumnya)
  6. mulai mysqld
  7. impor
  8. hentikan mysqld
  9. salin / var / lib / mysql ke mysql2
  10. umount mysql; rmdir mysql
  11. pindahkan mysql2 ke mysql
  12. mulai mysqld, senanglah

Bagi saya, dump ~ 10G (/ var / lib / mysql mengkonsumsi ~ 20G) dapat diimpor dalam waktu sekitar 35 menit (mydumper / myloader), 45 menit (mysqldump --tab / mysqlimport), 50 menit (mysqldump / mysql) , pada Xeon 2x6-core 3.2GHz.

Jika Anda tidak memiliki cukup RAM dalam satu mesin, tetapi memiliki beberapa komputer yang bersebelahan dengan jaringan cepat, akan menarik untuk melihat apakah RAM mereka dapat digabungkan dengan nbd (perangkat blok jaringan). Atau, dengan innodb_file_per_table, Anda mungkin dapat mengulangi proses di atas untuk setiap tabel.

egmont
sumber
Karena penasaran saya mencoba menyimpan datadir mysql di RAM untuk membandingkannya dengan SSD (SSDSC2BB48 untuk mereka yang tertarik) untuk database 2 GB. Hasilnya adalah IDENTIK, keduanya membutuhkan waktu 207-209 detik. Mempertimbangkan fakta bahwa Anda juga harus memulai / menghentikan mysql dan menyalin direktori, menggunakan disk RAM dan bukannya SSD jauh lebih lambat dalam kasus saya
Shocker
Jika Anda butuh waktu 3-4 menit, saya kira Anda memiliki basis data yang jauh lebih kecil daripada topik ini. Sangat menarik untuk mendengar tentang pengalaman Anda dengan database yang sama besar dari yang disebutkan dalam topik ini.
egmont