ฉันมีประมาณ 40 ล้านแถวในตาราง MySQL และฉันต้องการคัดลอกตารางนี้ไปยังตารางอื่นในฐานข้อมูลเดียวกัน วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนี้คืออะไร? ใช้เวลานานเท่าไร (ประมาณ)
ฉันมีประมาณ 40 ล้านแถวในตาราง MySQL และฉันต้องการคัดลอกตารางนี้ไปยังตารางอื่นในฐานข้อมูลเดียวกัน วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนี้คืออะไร? ใช้เวลานานเท่าไร (ประมาณ)
คำตอบ:
สมมติว่าคุณมีmydb.mytb
และคุณต้องการสร้างmydb.mytbcopy
ฉันมีห้า (5) วิธีในการทำสำเนานี้
ในmysql
ไคลเอนต์เรียกใช้ต่อไปนี้
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}
หากคุณต้องการคัดลอกmydb.mytb
ไปยังตารางที่มีอยู่แล้วmydb.mytbcopy
และทั้งสองตารางมีโครงสร้างที่เหมือนกัน:
INSERT INTO mytbcopy SELECT * FROM mytb;
เช่นเดียวกับ#APPROACH 1 , #APPROACH 6จะมีการทำรายการเดียว 40 ล้านแถว
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
วิธีนี้ไม่ได้ลดลงในตาราง มันเพียงสร้าง INSERT
ฉันไม่สามารถประมาณการเวลาให้คุณได้เนื่องจากฉันไม่รู้การสร้าง DB Server โครงสร้างตารางเค้าโครงของดัชนีและสิ่งต่าง ๆ เหล่านี้
ตาราง InnoDB ซึ่งแตกต่างจาก MyISAM * ไม่สามารถ "เพิ่งคัดลอกออกไป" ซึ่งเป็นส่วนหนึ่งของพจนานุกรมข้อมูล (และโครงสร้างอื่น ๆ ที่อาจเกิดขึ้นตารางขึ้นอยู่กับเช่นบัฟเฟอร์ผสาน) ตั้งอยู่ในหน่วยความจำ (หากเซิร์ฟเวอร์กำลังทำงาน) และใน ทั่วไป / ibdata1
ตารางหลักหรือที่รู้จักว่าไฟล์ขนาดใหญ่ที่เรียกว่า
หากคุณใช้ Percona Server> = 5.1 หรือ MySQL> = 5.6 มีการรองรับพื้นที่ตารางที่สามารถเคลื่อนย้ายได้ซึ่งช่วยให้คุณสามารถส่งออกและนำเข้าตารางโดยตรงจากระบบไฟล์ นี่มันเป็นวิธีการในการMySQLและPercona ในทั้งสองกรณีคุณจำเป็นต้องสร้างตารางด้วยinnodb_file_per_table
ตัวเลือกและเกี่ยวข้องกับการใช้งานDISCARD TABLESPACE/IMPORT TABLESPACE
และ / หรือ Percona Xtrabakup (หากคุณต้องการให้การส่งออกออนไลน์เสร็จสิ้น) โปรดทราบว่าเซิร์ฟเวอร์ Percona หรือ Xtrabakup ไม่สามารถใช้งานได้กับ Windows
วิธีนี้จะพูดโดยทั่วไปให้เร็วที่สุดเท่าที่คัดลอกไฟล์โดยใช้คำสั่งระบบไฟล์ (cp, rsync)
ในขณะที่อาจมีบางกรณีที่สิ่งนี้สามารถทำงานได้ใน MySQL <5.6 (ในทางที่แฮ็ก) สำหรับการกู้คืนมันจะไม่ทำงานสำหรับสำเนาตาราง ในกรณีเหล่านั้นวิธีหนึ่งที่ทำได้คือใช้ SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
สิ่งนี้จะเร็วเท่าที่ InnoDB สามารถดำเนินการได้ Handler_read_rnd_next
และHandler_write
หนึ่งครั้งต่อแถว ถ้าคุณใช้วิธีนี้ตรวจสอบให้แน่ใจว่าคุณปิดใช้งานตัวเลือกความทนทานอย่างน้อยก็ชั่วคราวและคุณมีพูลบัฟเฟอร์ขนาดใหญ่และบันทึกธุรกรรม ภายใต้สถานการณ์เหล่านั้นอาจลดเวลาการนำเข้า แต่จะไม่พอดีกับหน่วยความจำอย่างแน่นอนดังนั้นคาดว่าจะมีเวลามาก นอกจากนี้คุณกำลังพยายามนำเข้าแถว 40M ในธุรกรรมเดียวซึ่งอาจนำไปสู่ปัญหา
ข้อเสนอแนะที่แท้จริงของฉันในกรณีที่สองนี้คือใช้บางอย่างเช่นpt-archiverเนื่องจากมันจะทำงานคล้ายกับที่ฉันเพิ่งพูดถึง แต่มันจะทำในรูปแบบ "chunks" โดยหลีกเลี่ยงค่าใช้จ่ายในการทำธุรกรรม (อาจ ไม่เร็วกว่านี้ แต่ในกรณีที่เกิดข้อผิดพลาดมันจะไม่พยายามย้อนกลับตารางทั้งหมด สำหรับขนาดข้อมูลที่คุณพูดถึงนี่อาจเป็นวิธีที่ดีที่สุด
ตัวเลือกสุดท้ายคือการส่งออกและนำเข้าโดยใช้รูปแบบ CSV (หรือ TSV)ด้วยการรวมกันของ SELECT INTO OUTFILE / mysqldump และ LOAD DATA / mysqlimport นี่เป็นตัวเลือกที่พบบ่อยมากหากคุณต้องการใช้งานพร้อมกันใน mysql รุ่นเก่าบางรุ่นเนื่องจากการใช้ sql สร้างการล็อคที่มีขนาดใหญ่ขึ้น เนื่องจาก mysqldump / import ทำงานในลักษณะอนุกรมเท่านั้นฉันจึงขอแนะนำให้คุณทำการวิจัยตัวเลือกในการขนานมันซึ่งมีประโยชน์มากสำหรับตารางขนาดใหญ่
ไม่ว่าในกรณีใดพยายามหลีกเลี่ยงประโยค SQL หลายประโยคเนื่องจากมันจะเป็นปัญหาคอขวดที่สำคัญที่สุดของคุณหากคุณเรียกใช้คิวรีที่แตกต่างกัน (ซึ่งจะต้องดำเนินการแยกวิเคราะห์และปรับให้เหมาะสมทีละรายการ)
* โครงสร้าง MyISAM ไม่สามารถคัดลอกในทางที่ร้อน FTWRL
แต่มันเป็นเรื่องง่ายมากที่จะซิงค์พวกเขาไปยังดิสก์ชั่วคราวด้วย
เพื่อย้ายข้อมูลจากตารางหนึ่งไปอีกตารางหนึ่งในสคีมา
create table your_table_name select * from old_schema_table;