Saya berjuang dengan mengimpor sebagian besar InnoDB-Table cukup besar yang terdiri dari sekitar 10 Juta baris (atau 7GB) (yang bagi saya adalah meja terbesar yang pernah saya kerjakan sejauh ini).
Saya melakukan riset bagaimana meningkatkan kecepatan impor Inno dan untuk saat ini setup saya terlihat seperti ini:
/etc/mysql/my.cnf/
[...]
innodb_buffer_pool_size = 7446915072 # ~90% of memory
innodb_read_io_threads = 64
innodb_write_io_threads = 64
innodb_io_capacity = 5000
innodb_thread_concurrency=0
innodb_doublewrite = 0
innodb_log_file_size = 1G
log-bin = ""
innodb_autoinc_lock_mode = 2
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit=2
innodb_buffer_pool_instances=8
import is done via bash script, here is the mysql code:
SET GLOBAL sync_binlog = 1;
SET sql_log_bin = 0;
SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET AUTOCOMMIT = 0;
SET SESSION tx_isolation='READ-UNCOMMITTED';
LOAD DATA LOCAL INFILE '$filepath' INTO TABLE monster
COMMIT;
Data disediakan dalam CSV
file.
Saat ini saya menguji pengaturan saya dengan 'test dumps' yang lebih kecil dengan 2 juta, 3 juta, ... masing-masing baris dan digunakan time import_script.sh
untuk membandingkan kinerja.
Kekurangannya adalah saya hanya mendapatkan waktu berjalan keseluruhan jadi saya harus menunggu impor penuh selesai untuk mendapatkan hasil.
Hasil saya sejauh ini:
- 10 000 baris: <1 detik
- 100.000 baris: 10 detik
- 300.000 baris: 40 detik
- 2 juta baris: 18 menit
- 3 juta baris: 26 menit
- 4 juta baris: (dibatalkan setelah 2 jam)
Tampaknya tidak ada solusi 'buku masak' dan kita harus mencari tahu kombinasi yang optimal dari pengaturan mereka sendiri.
Selain saran tentang apa yang harus diubah dalam pengaturan saya, saya juga akan sangat menghargai informasi lebih lanjut bagaimana saya bisa melakukan benchmark proses impor yang lebih baik / mendapatkan lebih banyak wawasan tentang apa yang terjadi dan di mana kemacetan mungkin terjadi.
Saya mencoba membaca dokumentasi untuk pengaturan yang saya ubah tetapi sekali lagi saya tidak mengetahui adanya efek samping dan jika saya bahkan menurunkan kinerja dengan nilai yang dipilih dengan buruk.
Untuk saat ini saya ingin mencoba saran dari obrolan untuk digunakan MyISAM
selama impor dan mengganti mesin tabel sesudahnya.
Saya ingin mencoba ini tetapi untuk saat ini DROP TABLE
permintaan saya juga membutuhkan waktu berjam-jam untuk menyelesaikannya. (Yang sepertinya indikator lain pengaturan saya kurang optimal).
Informasi tambahan:
Mesin yang saya gunakan saat ini memiliki 8GB RAM dan hard drive Solid State Hybrid w / 5400RPM.
Sementara kami juga bertujuan untuk menghapus data yang tidak terpakai dari tabel yang dimaksud, saya masih memerlukan impor yang agak cepat untuk
a) menguji automatic data cleanup feature
sementara mengembangkan dan
b) seandainya server kami mogok kami ingin menggunakan server 2 kami sebagai pengganti (yang membutuhkan data terkini, impor terakhir memakan waktu lebih dari 24 jam)
mysql> SHOW CREATE TABLE monster\G
*************************** 1. row ***************************
Table: monster
Create Table: CREATE TABLE `monster` (
`monster_id` int(11) NOT NULL AUTO_INCREMENT,
`ext_monster_id` int(11) NOT NULL DEFAULT '0',
`some_id` int(11) NOT NULL DEFAULT '0',
`email` varchar(250) NOT NULL,
`name` varchar(100) NOT NULL,
`address` varchar(100) NOT NULL,
`postcode` varchar(20) NOT NULL,
`city` varchar(100) NOT NULL,
`country` int(11) NOT NULL DEFAULT '0',
`address_hash` varchar(250) NOT NULL,
`lon` float(10,6) NOT NULL,
`lat` float(10,6) NOT NULL,
`ip_address` varchar(40) NOT NULL,
`cookie` int(11) NOT NULL DEFAULT '0',
`party_id` int(11) NOT NULL,
`status` int(11) NOT NULL DEFAULT '2',
`creation_date` datetime NOT NULL,
`someflag` tinyint(1) NOT NULL DEFAULT '0',
`someflag2` tinyint(4) NOT NULL,
`upload_id` int(11) NOT NULL DEFAULT '0',
`news1` tinyint(4) NOT NULL DEFAULT '0',
`news2` tinyint(4) NOT NULL,
`someother_id` int(11) NOT NULL DEFAULT '0',
`note` varchar(2500) NOT NULL,
`referer` text NOT NULL,
`subscription` int(11) DEFAULT '0',
`hash` varchar(32) DEFAULT NULL,
`thumbs1` int(11) NOT NULL DEFAULT '0',
`thumbs2` int(11) NOT NULL DEFAULT '0',
`thumbs3` int(11) NOT NULL DEFAULT '0',
`neighbours` tinyint(4) NOT NULL DEFAULT '0',
`relevance` int(11) NOT NULL,
PRIMARY KEY (`monster_id`),
KEY `party_id` (`party_id`),
KEY `creation_date` (`creation_date`),
KEY `email` (`email`(4)),
KEY `hash` (`hash`(8)),
KEY `address_hash` (`address_hash`(8)),
KEY `thumbs3` (`thumbs3`),
KEY `ext_monster_id` (`ext_monster_id`),
KEY `status` (`status`),
KEY `note` (`note`(4)),
KEY `postcode` (`postcode`),
KEY `some_id` (`some_id`),
KEY `cookie` (`cookie`),
KEY `party_id_2` (`party_id`,`status`)
) ENGINE=InnoDB AUTO_INCREMENT=13763891 DEFAULT CHARSET=utf8
sumber
SHOW CREATE TABLE yourtable\G
untuk menunjukkan kepada kami struktur tabel dari 10 juta baris tabel ini.innodb_doublewrite = 0
) instalasi MySQL Anda tidak aman crash: jika Anda mengalami kegagalan daya (bukan crash MySQL), data Anda mungkin rusak secara diam-diam.Jawaban:
Pertama, Anda perlu tahu apa yang Anda lakukan pada InnoDB ketika Anda membajak jutaan baris ke dalam tabel InnoDB. Mari kita lihat Arsitektur InnoDB.
Di sudut kiri atas, ada ilustrasi Pool Buffer InnoDB. Perhatikan ada bagian yang didedikasikan untuk menyisipkan penyangga. Apa fungsinya? Ia diminta untuk memigrasikan perubahan ke indeks sekunder dari Buffer Pool ke Insert Buffer di dalam tablespace sistem (alias ibdata1). Secara default, innodb_change_buffer_max_size diatur ke 25. Ini berarti bahwa hingga 25% dari Buffer Pool dapat digunakan untuk memproses indeks sekunder.
Dalam kasus Anda, Anda memiliki 6,935 GB untuk InnoDB Buffer Pool. Maksimum 1,734 GB akan digunakan untuk memproses indeks sekunder Anda.
Sekarang, lihat meja Anda. Anda memiliki 13 indeks sekunder. Setiap baris yang Anda proses harus menghasilkan entri indeks sekunder, pasangkan dengan kunci utama dari baris tersebut, dan kirim sebagai pasangan dari Sisipkan Penyangga di Kumpulan Penyangga ke Sisipkan Penyangga di ibdata1. Itu terjadi 13 kali dengan setiap baris. Kalikan ini dengan 10 juta dan Anda hampir bisa merasakan hambatan datang.
Jangan lupa bahwa mengimpor 10 juta baris dalam satu transaksi akan menumpuk semuanya menjadi satu segmen rollback dan mengisi ruang UNDO di ibdata1.
SARAN
SARAN # 1
Saran pertama saya untuk mengimpor tabel yang agak besar ini
SARAN # 2
Singkirkan indeks rangkap. Dalam kasus Anda, Anda punya
Kedua indeks dimulai dengan
party_id
, Anda dapat meningkatkan pemrosesan indeks sekunder dengan setidaknya 7,6% menyingkirkan satu indeks dari 13. Anda akhirnya harus menjalankanSARAN # 3
Singkirkan indeks yang tidak Anda gunakan. Lihatlah kode aplikasi Anda dan lihat apakah pertanyaan Anda menggunakan semua indeks. Anda mungkin ingin melihat penggunaan indeks pt untuk membiarkannya menyarankan indeks apa yang tidak digunakan.
SARAN # 4
Anda harus meningkatkan innodb_log_buffer_size menjadi 64M karena standarnya adalah 8M. Buffer log yang lebih besar dapat meningkatkan kinerja I / O InnoDB.
EPILOG
Dengan menerapkan dua saran pertama, lakukan yang berikut:
party_id
indeksMungkin yang berikut bisa membantu
Impor data ke
monster
. Lalu, jalankan iniCOBALAH !!!
ALTERNATIF
Anda bisa membuat tabel yang disebut
monster_csv
sebagai tabel MyISAM tanpa indeks dan melakukan ini:Impor data Anda ke
monster_csv
. Kemudian, gunakan mysqldump untuk membuat impor lainFile mysqldump
data.sql
akan memperpanjang perintah INSERT yang mengimpor 10.000-20.000 baris sekaligus.Sekarang, muat mysqldump
Akhirnya, singkirkan tabel MyISAM
sumber
monster
tabel) dalam waktu kurang dari 20 menit ketika tidak memiliki kunci pada tabel InnoDB. Menambahkan kunci membutuhkan sekitar. 20 menit lagi. Saya akan mengatakan ini cukup banyak memecahkan masalah saya dalam kasus ini. Terima kasih banyak!Saya ingin menulis komentar (karena ini bukan jawaban yang pasti), tetapi terlalu lama:
Saya akan memberikan beberapa saran luas kepada Anda, dan kami dapat memerinci masing-masing, jika Anda ingin:
Ingatlah bahwa beberapa di antaranya tidak aman atau disarankan untuk non-impor (operasi normal).
sumber
SET SESSION tx_isolation='READ-UNCOMMITTED';
(hanya berguna jika Anda mengimpor dengan beberapa utas secara paralel) dan komentar @ypercube tentang memasukkan bets. Anda memiliki contoh lengkap di sini: mysqlperformanceblog.com/2008/07/03/... Pastikan Anda mendapatkan keuntungan dari semua fitur di versi InnoDB terbaru: mysqlperformanceblog.com/2011/01/07/…Sebagian besar tips yang baik telah diberikan sejauh ini, tetapi tanpa banyak penjelasan untuk yang terbaik. Saya akan memberikan lebih banyak detail.
Pertama, menunda pembuatan indeks adalah yang baik, dengan rincian yang cukup dalam tanggapan lain. Saya tidak akan kembali lagi.
File log InnoDB yang lebih besar akan banyak membantu Anda (jika Anda menggunakan MySQL 5.6 karena tidak mungkin untuk meningkatkannya di MySQL 5.5). Anda memasukkan 7 GB data, saya akan merekomendasikan ukuran total log minimal 8 GB (tetap
innodb_log_files_in_group
pada default-nya (2) dan menabrakinnodb_log_file_size
pada 4 GB). 8 GB ini tidak tepat: harus setidaknya ukuran impor di log REDO dan mungkin dua kali lipat atau empat kali lipat ukuran itu. Alasan di balik ukuran log InnoDB meningkatkannya bahwa ketika log akan menjadi hampir penuh, InnoDB akan mulai menyiram kolam penyangga secara agresif ke disk untuk menghindari log pengisian (ketika log penuh, InnoDB tidak dapat melakukan penulisan database sampai beberapa halaman kumpulan buffer ditulis ke disk).File log InnoDB yang lebih besar akan membantu Anda, tetapi Anda juga harus memasukkan urutan kunci primer (urutkan file Anda sebelum memasukkan). Jika Anda memasukkan urutan kunci utama, InnoDB akan mengisi satu halaman, lalu satu lagi, dan seterusnya. Jika Anda tidak memasukkan urutan kunci utama, masukkan berikutnya mungkin berakhir di halaman yang penuh dan akan menimbulkan "pemisah halaman". Pemecahan halaman ini akan mahal untuk InnoDB dan akan memperlambat impor Anda.
Anda sudah memiliki buffer pool sebesar RAM yang memungkinkan dan jika meja Anda tidak pas, tidak banyak yang bisa Anda lakukan kecuali membeli lebih banyak RAM. Tetapi jika tabel Anda cocok dalam buffer pool tetapi lebih besar dari 75% pool buffer Anda, Anda dapat mencoba meningkatkan
innodb_max_dirty_pages_pct
ke 85 atau 95 selama impor (nilai defaultnya adalah 75). Parameter konfigurasi ini memberi tahu InnoDB untuk memulai pembilasan kolam penyangga secara agresif ketika persentase halaman kotor mencapai batas ini. Dengan menaikkan parameter ini (dan jika Anda beruntung dengan ukuran data), Anda mungkin menghindari IO agresif selama impor dan menunda IO tersebut nanti.Mungkin (dan ini dugaan) mengimpor data Anda dalam banyak transaksi kecil akan membantu Anda. Saya tidak tahu persis bagaimana REDO log dibangun, tetapi jika itu buffered dalam RAM (dan disk ketika terlalu banyak RAM akan dibutuhkan) saat transaksi sedang membuat kemajuan, Anda mungkin berakhir dengan IO yang tidak perlu. Anda dapat mencoba ini: setelah file Anda diurutkan, pisahkan dalam banyak potongan (coba dengan 16 MB dan ukuran lainnya) dan impor satu per satu. Ini juga akan memungkinkan Anda untuk mengontrol kemajuan impor Anda. Jika Anda tidak ingin data Anda terlihat sebagian oleh pembaca lain saat Anda melakukan impor, Anda bisa mengimpor menggunakan nama tabel yang berbeda, membuat indeks nanti, dan kemudian mengganti nama tabel.
Tentang disk SSD / 5400RPM hibrid Anda, saya tidak tahu tentang itu dan bagaimana mengoptimalkannya. 5400RPM terlihat lambat untuk basis data, tetapi mungkin SSD menghindarinya. Tentu saja Anda mengisi bagian SSD dari disk Anda dengan menulis berurutan ke REDO log dan SSD merusak kinerja. Saya tidak tahu.
Kiat buruk yang tidak boleh Anda coba (atau berhati-hati) adalah sebagai berikut: jangan gunakan multi-utas: akan sangat sulit untuk mengoptimalkan untuk menghindari pemisahan halaman di InnoDB. Jika Anda ingin menggunakan multi-utas, masukkan dalam tabel yang berbeda (atau di partisi berbeda dari tabel yang sama).
Jika Anda mempertimbangkan multi-thread, mungkin Anda memiliki komputer multi-socket (NUMA). Dalam hal ini, pastikan Anda menghindari masalah kegilaan swap MySQL .
Jika Anda menggunakan MySQL 5.5, tingkatkan ke MySQL 5.6: ia memiliki opsi untuk meningkatkan ukuran log REDO dan memiliki algoritma penyiraman pool penyangga yang lebih baik.
Semoga berhasil dengan impor Anda.
sumber