แปลงตารางแถว 66,862,521 จาก MyISAM เป็น InnoDB โดยไม่ต้องออฟไลน์เป็นเวลาหลายชั่วโมงได้อย่างไร


18

เป็นไปได้ (และวิธี) ในการแปลงตาราง MyISAM ขนาดใหญ่เป็น InnoDB โดยไม่ต้องสมัครออฟไลน์ ต้องมีการแทรกสองแถวลงในตารางนั้นทุกวินาที แต่สามารถระงับได้ประมาณ 2 นาที

เห็นได้ชัดว่าเปลี่ยนแปลงตาราง ... engine = innodb จะไม่ทำงาน ดังนั้นฉันจึงวางแผนที่จะสร้างตารางใหม่พร้อมกับเครื่องยนต์ innodb และคัดลอกเนื้อหาลงไป และในท้ายที่สุดระงับเธรดแอปพลิเคชันเธรดและ RENAME TABLE

น่าเสียดายที่แม้แต่การทำสำเนาในแบทช์ขนาดเล็กจำนวน 100 แถวก็สร้างความล่าช้าอย่างมากหลังจากผ่านไประยะหนึ่ง

แก้ไข : แถวที่มีอยู่จะไม่เปลี่ยนแปลงตารางนี้ใช้สำหรับการบันทึก



3
คำถามนั้นเกี่ยวกับการลดเวลาการสนทนา ฉันไม่สนใจว่าการสนทนาใช้เวลาสองสามวันหรือหลายสัปดาห์ แต่จะต้องทำงานในพื้นหลังโดยไม่ต้องใช้เวลาลงของแอปพลิเคชันและไม่สร้างความล่าช้าที่เห็นได้ชัดเจน
Hendrik Brummermann

คำตอบ:


15

สร้างการตั้งค่า Master-Master ดังต่อไปนี้:

  • สร้างต้นแบบที่สอง MasterB
  • MasterB ทำหน้าที่เป็นทาสให้กับ logTable
  • สร้างlogTable_newเป็น innodb
  • Run INSERT INTO logTable_new SELECT * FROM logTable(psuedocode) บน MasterB ซึ่งส่งการจำลองแบบไปยัง MasterA
  • เมื่อlogTable_newMasterA ซิงค์เสร็จแล้วให้สลับตาราง

10

รับข้อ จำกัด ของ:

ฉันไม่สนใจว่าการสนทนาใช้เวลาสองสามวันหรือหลายสัปดาห์ แต่มันจะต้องทำงานในพื้นหลังโดยไม่ต้องใช้เวลาในการลงโปรแกรมและไม่สร้างความล่าช้าที่เห็นได้ชัด

ในขณะที่คุณกำลังทำการบันทึกถ้าคุณมีวิธีที่ดีในการตั้งเครื่องหมายเพื่อให้คุณสามารถบอกได้ว่าคุณเริ่มต้นกระบวนการอะไรดังนั้นคุณจึงสามารถนำบันทึกใหม่มาใช้อีกครั้งหรือเขียนบันทึกลงในไฟล์ข้อความ คุณสามารถนำเข้าไปในภายหลังด้วย LOAD DATA INFILE

ส่วนหนึ่งของปัญหาคือการเขียนเป็นชุดเล็กหมายความว่าดัชนีจะต้องมีการคำนวณซ้ำแล้วซ้ำอีก คุณดีกว่าที่จะใช้งานทั้งหมดในคราวเดียว แต่สิ่งนี้อาจทำให้เกิดความล่าช้า 'ที่สังเกตได้' ในระบบ .. แต่คุณไม่จำเป็นต้องทำบนเซิร์ฟเวอร์ที่ใช้งานจริงของคุณ

  1. หยุดการบันทึกชั่วคราวหรือตั้งเครื่องหมายบางอย่างเพื่อให้คุณสามารถใช้บันทึกอีกครั้งจากจุดนี้ในภายหลัง
  2. คัดลอกตาราง MyISM ของคุณไปยังระบบอื่น
  3. บนระบบอื่นให้สร้างตาราง InnoDB ภายใต้ชื่ออื่นและย้ายข้อมูล (อาจเร็วกว่าในการถ่ายโอนข้อมูลและใช้LOAD DATA INFILE)
  4. คัดลอกตาราง InnoDB กลับสู่ระบบดั้งเดิม
  5. ตั้งเครื่องหมายอื่นสำหรับการบันทึก
  6. ใช้บันทึกทั้งหมดไปยังตารางใหม่อีกครั้งระหว่างเครื่องหมายสองอันสุดท้าย
  7. (ทำซ้ำขั้นตอนที่ 5 และ 6 หากขั้นตอนที่ # 6 ใช้เวลามากกว่าหนึ่งนาทีหรือมากกว่านั้นจนกว่าจะถึงเวลาเช่นนี้เพราะใช้เวลาเพียงไม่กี่วินาที)
  8. สลับตาราง (เปลี่ยนชื่อเก่าเป็น table_BACKUP อันใหม่ภายใต้ชื่อเก่า)
  9. ติดตามบันทึกตั้งแต่เครื่องหมายสุดท้าย

9

น่าเสียดายที่แม้แต่การทำสำเนาในแบทช์ขนาดเล็กจำนวน 100 แถวก็สร้างความล่าช้าอย่างมากหลังจากผ่านไประยะหนึ่ง

คุณเพิ่มการหน่วงเวลาระหว่างแต่ละชุดงานหรือเพียงแค่รวมชุดการปรับปรุงและเรียกใช้ชุดงานแต่ละชุดโดยตรงหลังจากชุดก่อนหน้าหรือไม่

ถ้าเป็นเช่นนั้นให้ลองเขียนสคริปต์การแปลงในภาษาที่คุณชื่นชอบด้วยสิ่งที่ชอบ:

repeat
    copy oldest 100 rows that haven't been copied yet to new table
    sleep for as long as that update took
until there are <100 rows unprocessed
stop logging service
move the last few rows
rename tables
restart logging
delete the old table when you are sure the conversion has worked

สิ่งนี้ควรตรวจสอบให้แน่ใจว่าการแปลงไม่ได้ใช้ความจุของเซิร์ฟเวอร์มากกว่าครึ่งหรือน้อยกว่าแม้จะให้ความแตกต่างของภาระที่กำหนดเนื่องจากการใช้งานของระบบแตกต่างกันไปตามเวลา

หรือถ้าคุณต้องการที่จะใช้เป็นเวลามากที่สุดเท่าที่เป็นไปได้เมื่อบริการที่ค่อนข้างไม่ได้ใช้งาน แต่กลับออก (อาจหยุดสำหรับค่อนข้างยาวของเวลา) เมื่อฐานข้อมูลความต้องการที่จะทำผลงานบางอย่างสำหรับผู้ใช้แทนที่ด้วยsleep for as long as the update took if the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>นี่หมายถึงว่ามันสามารถทำงานได้ล่วงหน้าในช่วงเวลาที่เงียบสงบ แต่จะหยุดชั่วขณะอย่างสมบูรณ์เมื่อเซิร์ฟเวอร์ไม่ว่างซึ่งทำงานเป็นภาระงานปกติ การพิจารณาโหลดจะขึ้นอยู่กับระบบปฏิบัติการของคุณ - ภายใต้ Linux และค่าเฉลี่ย 1 นาทีที่โหลดจาก/proc/loadavgหรือuptimeควรทำเช่นเดียวกัน <lower measure>และ<upper measure>อาจเป็นค่าเดียวกันแม้ว่าจะเป็นเรื่องปกติในการควบคุมเช่นนี้เพื่อให้มีความแตกต่างดังนั้นกระบวนการของคุณจะไม่เริ่มต้นแล้วหยุดทันทีทันทีเนื่องจากการรีสตาร์ทของตัวเองมีผลกับการวัดโหลด

แน่นอนว่าสิ่งนี้จะไม่ทำงานสำหรับตารางที่แถวเก่าอาจได้รับการแก้ไข แต่จะทำงานได้ดีสำหรับตารางบันทึกเช่นเดียวกับที่คุณอธิบาย

คุณจะต้องเพิกเฉยต่อภูมิปัญญาดั้งเดิมในการสร้างดัชนีหลังจากเติมตารางใหม่ในกรณีนี้ ในขณะที่มีประสิทธิภาพมากขึ้นเมื่อคุณต้องการให้สิ่งต่าง ๆ เร็วที่สุดเท่าที่จะเป็นไปได้ (ผลกระทบต่อส่วนที่เหลือของระบบจะถูกสาป) ในกรณีนี้คุณไม่ต้องการโหลดจำนวนมากในตอนท้ายของกระบวนการ ดัชนีถูกสร้างขึ้นอย่างสมบูรณ์ในครั้งเดียวเนื่องจากเป็นกระบวนการที่คุณไม่สามารถหยุดชั่วคราวเมื่อสิ่งต่างๆไม่ว่าง


4

อยากได้สิ่งนี้ไหม

  1. หยุดการบันทึกชั่วคราว (ดังนั้น$auto_incrementในตารางการบันทึกของคุณmytable จะไม่เปลี่ยนแปลง)
  2. หมายเหตุค่าใช้ $auto_incrementSHOW TABLE STATUS LIKE 'mytable'
  3. CREATE TABLE mytable_new LIKE mytable
  4. ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
  5. RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
  6. เปิดใช้งานการบันทึกอีกครั้ง ตาราง Innodb จะเริ่มทำการเติมข้อมูล
  7. INSERT INTO mytable SELECT * FROM mytable_old.

คุณสามารถทำขั้นตอนที่ 7 ในแบทช์หรือในคำสั่งเดียวเพราะมันไม่ควรจะบล็อกการบันทึกปกติ


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