คัดลอกจากตาราง MySQL หนึ่งไปยังอีกตาราง MySQL ของฐานข้อมูลเดียวกัน


15

ฉันมีประมาณ 40 ล้านแถวในตาราง MySQL และฉันต้องการคัดลอกตารางนี้ไปยังตารางอื่นในฐานข้อมูลเดียวกัน วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนี้คืออะไร? ใช้เวลานานเท่าไร (ประมาณ)


Engine ของตารางของคุณคืออะไร
Abdul Manaf

InnoDB Engine ..
Devashish Dixit

คำตอบ:


23

สมมติว่าคุณมีmydb.mytbและคุณต้องการสร้างmydb.mytbcopy

ฉันมีห้า (5) วิธีในการทำสำเนานี้

แนวทางที่ 1

ในmysqlไคลเอนต์เรียกใช้ต่อไปนี้

USE mydb
CREATE TABLE mytbcopy LIKE mytb;
INSERT INTO mytbcopy SELECT * FROM mytb;

แนวทางที่ 2

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"

แนวทางที่ 3

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"

แนวทางที่ 4

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

แนวทางที่ 5

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}

การวิเคราะห์

  • วิธีที่ # 1เป็นขั้นตอนที่ง่ายที่สุด แต่ต้องการผลักดัน 40 ล้านแถวให้เป็นธุรกรรมเดียว นี่จะเป็นการเสียภาษีมากที่สุดใน InnoDB Storage Engine
  • สำหรับวิธีอื่น mysqldump จะส่ง 40 ล้านแถวใน chucks ของหลายพันแถว
    • Approach # 2และApproach # 3จะ mysqldump ตารางลงในฐานข้อมูลทดสอบ หลังจากสร้างตารางในฐานข้อมูลทดสอบแล้วจะถูกเปลี่ยนชื่อและย้ายไปยังฐานข้อมูลเดิมในภายหลัง
    • Approach # 4และApproach # 5เปลี่ยนชื่อตารางโดยใช้sedต่อสตรีมที่มาจาก mysqldump ตามที่มันสะท้อนคำสั่ง INSERT
    • Approach # 2และApproach # 4ใช้ไพพ์แทนไฟล์เอาต์พุต
    • Approach # 3และApproach # 5ใช้ไฟล์ outpuit สำหรับการรีโหลดครั้งต่อไป

หากคุณต้องการคัดลอกmydb.mytbไปยังตารางที่มีอยู่แล้วmydb.mytbcopyและทั้งสองตารางมีโครงสร้างที่เหมือนกัน:

แนวทางที่ 6

INSERT INTO mytbcopy SELECT * FROM mytb;

เช่นเดียวกับ#APPROACH 1 , #APPROACH 6จะมีการทำรายการเดียว 40 ล้านแถว

แนวทางที่ 7

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 โครงสร้างตารางเค้าโครงของดัชนีและสิ่งต่าง ๆ เหล่านี้

ให้มันลอง !!!


0

ตาราง 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แต่มันเป็นเรื่องง่ายมากที่จะซิงค์พวกเขาไปยังดิสก์ชั่วคราวด้วย


0

เพื่อย้ายข้อมูลจากตารางหนึ่งไปอีกตารางหนึ่งในสคีมา

create table your_table_name select * from old_schema_table;

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.