Saya memiliki sekitar 40 juta baris dalam tabel MySQL dan saya ingin menyalin tabel ini ke tabel lain dalam database yang sama. Apa cara paling efisien untuk melakukan ini? Berapa lama waktu yang dibutuhkan (kurang-lebih)?
Saya memiliki sekitar 40 juta baris dalam tabel MySQL dan saya ingin menyalin tabel ini ke tabel lain dalam database yang sama. Apa cara paling efisien untuk melakukan ini? Berapa lama waktu yang dibutuhkan (kurang-lebih)?
Jawaban:
Misalkan Anda memiliki mydb.mytb
dan ingin membuatmydb.mytbcopy
Saya memiliki lima (5) pendekatan untuk melakukan salinan ini
Di mysql
klien, jalankan yang berikut ini
USE mydb
CREATE TABLE mytbcopy LIKE mytb;
INSERT INTO mytbcopy SELECT * FROM mytb;
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysql ${MYSQL_CONN} -ANe"CREATE DATABASE IF NOT EXISTS test"
mysqldump ${MYSQL_CONN} mydb mytb | mysql ${MYSQL_CONN} -Dtest
mysql ${MYSQL_CONN} -ANe"ALTER TABLE test.mytb RENAME mydb.mytbcopy"
DUMPFILE=/some/path/tabledata.sql
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysql ${MYSQL_CONN} -ANe"CREATE DATABASE IF NOT EXISTS test"
mysqldump ${MYSQL_CONN} mydb mytb > ${DUMPFILE}
mysql ${MYSQL_CONN} -Dtest < ${DUMPFILE}
rm -f ${DUMPFILE}
mysql ${MYSQL_CONN} -ANe"ALTER TABLE test.mytb RENAME mydb.mytbcopy"
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} mydb mytb | sed 's/mytb/mytbcopy' | mysql ${MYSQL_CONN} -Dmydb
DUMPFILE=/some/path/tabledata.sql
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} mydb mytb | sed 's/mytb/mytbcopy' > ${DUMPFILE}
mysql ${MYSQL_CONN} -Dmydb < ${DUMPFILE}
rm -f ${DUMPFILE}
Jika Anda ingin menyalin mydb.mytb
ke tabel yang sudah ada mydb.mytbcopy
, dan kedua tabel memiliki struktur yang identik:
INSERT INTO mytbcopy SELECT * FROM mytb;
Seperti #APPROACH 1 , #APPROACH 6 akan memiliki satu transaksi 40 juta baris
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} -t mydb mytb | sed 's/mytb/mytbcopy' | mysql ${MYSQL_CONN} -Dmydb
Pendekatan ini tidak menjatuhkan tabel. Ini hanya menghasilkan INSERT
Saya tidak bisa memberi Anda perkiraan waktu karena saya tidak tahu susunan DB Server, struktur tabel, tata letak indeks, dan hal-hal seperti ini.
Tabel InnoDB, tidak seperti MyISAM *, tidak dapat "disalin begitu saja", sebagai bagian dari kamus datanya (dan berpotensi struktur lain yang bergantung pada tabel, seperti buffer gabungan) terletak di memori (jika server sedang berjalan) dan di tablespace umum / utama, alias file besar yang disebut ibdata1
.
Jika Anda menggunakan Percona Server> = 5.1 atau MySQL> = 5.6, ada dukungan untuk tablespace yang dapat diangkut, yang memungkinkan Anda untuk mengekspor dan mengimpor tabel secara langsung dari sistem file. Ini dia metode untuk MySQL dan untuk Percona . Dalam kedua kasus, Anda harus membuat tabel denganinnodb_file_per_table
opsi dan melibatkan penggunaan DISCARD TABLESPACE/IMPORT TABLESPACE
dan / atau Percona Xtrabakup (jika Anda ingin ekspor dilakukan secara online). Harap dicatat bahwa Percona Server atau Xtrabakup tidak tersedia untuk Windows.
Metode ini akan, secara umum, secepat menyalin file menggunakan perintah filesystem (cp, rsync).
Walaupun mungkin ada beberapa kasus bahwa ini bisa bekerja di MySQL <5.6 (dengan cara hacky) untuk mengembalikan, itu tidak akan berfungsi untuk salinan tabel. Dalam kasus tersebut, salah satu cara untuk melakukannya adalah dengan menggunakan SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Ini akan secepat yang InnoDB dapat jalankan Handler_read_rnd_next
danHandler_write
, sekali per baris. Jika Anda menggunakan metode ini, pastikan bahwa Anda menonaktifkan, setidaknya untuk sementara, opsi daya tahan dan Anda memiliki kumpulan buffer besar dan log transaksi. Dalam keadaan seperti itu, ini dapat mengurangi waktu impor, tetapi pasti tidak akan masuk ke memori sepenuhnya, jadi harap banyak waktu. Selain itu, Anda mencoba mengimpor 40 juta baris dalam satu transaksi, yang dapat menyebabkan masalah.
Rekomendasi saya yang sebenarnya, dalam kasus kedua ini, adalah menggunakan sesuatu seperti pt-archiver , karena akan melakukan operasi yang mirip dengan yang saya sebutkan, tetapi akan dilakukan dalam "bongkahan", menghindari overhead transaksional (mungkin overhead tidak lebih cepat, tetapi dalam kasus kegagalan, itu tidak akan mencoba untuk mengembalikan seluruh tabel, mengambil selamanya). Untuk ukuran data yang Anda sebutkan, ini mungkin cara terbaik untuk melakukannya.
Opsi terakhir adalah mengekspor dan mengimpor menggunakan format CSV (atau TSV) , dengan kombinasi SELECT INTO OUTFILE / mysqldump dan LOAD DATA / mysqlimport. Ini adalah pilihan yang sangat umum jika Anda membutuhkan konkurensi dalam versi lama mysql, karena menggunakan sql membuat kunci lebih besar (tidak benar lagi jika dilakukan dengan benar). Karena mysqldump / import hanya berfungsi secara serial, saya akan merekomendasikan Anda untuk meneliti opsi untuk memparalelkannya, sangat berguna untuk tabel besar.
Bagaimanapun, cobalah untuk menghindari beberapa kalimat SQL, karena itu akan menjadi hambatan Anda yang paling penting jika Anda menjalankan banyak pertanyaan yang berbeda (yang harus dieksekusi, diuraikan dan dioptimalkan secara individual).
* Struktur MyISAM tidak dapat disalin dengan cara yang panas, tetapi sangat mudah untuk menyinkronkannya sementara ke disk dengan FTWRL
.
untuk Memindahkan data dari satu tabel ke tabel lainnya dalam skema
create table your_table_name select * from old_schema_table;