วิธีเพิ่มคอลัมน์ในตารางขนาดใหญ่ใน MySQL


13

ฉันเป็นนักพัฒนา PHP ดังนั้นอย่าเข้มงวด ฉันมีตารางขนาดใหญ่ ~ 5.5gb dump PM ของเราตัดสินใจที่จะสร้างคอลัมน์ใหม่เพื่อดำเนินการคุณสมบัติใหม่ ตารางคือ InnoDB ดังนั้นสิ่งที่ฉันลอง:

  1. เปลี่ยนตารางในหน้าจอพร้อมล็อคตาราง เอา ~ 30 ชั่วโมงและไม่มีอะไร ดังนั้นฉันแค่หยุดมัน ครั้งแรกที่ฉันทำผิดเพราะฉันไม่ได้จบการทำธุรกรรมทั้งหมด แต่ครั้งที่ 2 ไม่มีมัลติเลค copy to tmp tableสถานะเป็น

  2. เนื่องจากฉันต้องใช้การแบ่งพาร์ติชันสำหรับตารางนี้เราจึงตัดสินใจทำการดัมพ์เปลี่ยนชื่อและสร้างตารางด้วยชื่อเดียวกันและโครงสร้างใหม่ แต่การถ่ายโอนข้อมูลกำลังทำสำเนาอย่างเข้มงวด (อย่างน้อยฉันก็ไม่พบสิ่งอื่นใด) ดังนั้นฉันจึงเพิ่มการถ่ายโอนข้อมูลคอลัมน์ใหม่ด้วยsedและสอบถาม แต่มีข้อผิดพลาดแปลก ๆ เกิดขึ้น ฉันเชื่อว่ามันเกิดจากชุดอักขระ ตารางในไฟล์ UTF-8 และกลายเป็น ASCII sedสหรัฐอเมริกาหลังจากที่ ดังนั้นฉันจึงได้รับข้อผิดพลาด (ไม่ทราบคำสั่ง '\' ') จากข้อมูล 30% ดังนั้นนี่เป็นวิธีที่ไม่ดี

ตัวเลือกอื่น ๆ ในการทำสิ่งนี้ให้สำเร็จและเพิ่มประสิทธิภาพความเร็ว (ฉันสามารถทำได้ด้วยสคริปต์ PHP แต่จะใช้เวลานาน) สิ่งที่จะเป็นประสิทธิภาพของINSERT SELECTในกรณีนี้

ขอบคุณล่วงหน้า

คำตอบ:


12

ใช้MySQL Workbench คุณสามารถคลิกขวาที่ตารางและเลือก "ส่งไปยัง SQL Editor" -> "สร้างคำสั่ง" วิธีนี้จะไม่มีการลืมคุณสมบัติ "ของตาราง" (รวมถึงCHARSETหรือCOLLATE)
ด้วยข้อมูลจำนวนมหาศาลนี้ฉันขอแนะนำให้ล้างตารางหรือโครงสร้างข้อมูลที่คุณใช้ (DBA ที่ดีมีประโยชน์) หากไม่สามารถทำได้:

  • เปลี่ยนชื่อตาราง ( ALTER) และสร้างใหม่ด้วยCREATEสคริปต์ที่คุณได้รับจาก Workbench คุณสามารถขยายคิวรีนั้นด้วยฟิลด์ใหม่ที่คุณต้องการ
  • โหลดข้อมูลจำนวนมากจากโต๊ะเก่าไปยังตารางใหม่:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;
    

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

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

ตัวเลือกของฉันไม่เป็นไร และฉันได้SET NAMES utf8และCOLLATION.But Meh idk ทำไม 30% sedของข้อมูลที่เสียหายหลังจาก ฉันคิดว่าการโหลดจำนวนมากจะเร็วที่สุด แต่อาจมีบางอย่างที่ฉันขาดหายไป ขอบคุณ Mark
ineersa

1
@ineersa ความเสียหายของข้อมูลอาจมีสาเหตุหลายประการเช่นคุณเปิดไฟล์ด้วยเครื่องมือแก้ไขที่ไม่สนับสนุนตัวอักษรทั้งหมดและบันทึกไว้ หรือวิธีที่คุณพยายามนำเข้าจากการถ่ายโอนข้อมูลทำให้เกิดความเสียหาย (เป็นรถบั๊กและไม่สามารถอ่านไฟล์ได้อย่างถูกต้อง) หรือคนเดียวกันอาจระบุส่วนของข้อมูลบางส่วนเป็นนิพจน์ (เช่น "james \ robin" == "\ r" เป็นนิพจน์) หรือคำสั่ง ฯลฯ นี่คือเหตุผลที่ฉันไม่แนะนำให้ใช้ดัมพ์แม้จะใช้เครื่องมือดัมพ์ข้อมูลไบนารี เท่านั้นไม่ใช่แม้แต่กับdev.mysql.com/doc/refman/5.6/en/mysqldump.html (หรือ BCP สำหรับ MS SQL Server) มันผิดพลาดหลายครั้งเกินไป ...

อ๋อฉันลองด้วย hex-blob มันไม่ช่วย นอกจากนี้คุณทันทีหลังจากใช้ sed mysql ระบุ \ 'เป็นคำสั่งในบางชื่อ (ไม่ใช่ทั้งหมด) นั่นเป็นเรื่องที่แปลกและบั๊กกี้ จะลองโหลดจำนวนมากคืนนี้ หวังว่ามันจะทำได้อย่างน้อย 10-15 ชั่วโมง
ineersa

@ineersa หวังว่ามันจะ คุณสามารถลองเพิ่มเพียงบางส่วนของข้อมูลสมมติว่า 10% ของข้อมูลเพื่อดูว่าต้องใช้เวลานานเท่าใดและมีการประมาณการสำหรับธุรกรรมทั้งหมด มันจะเป็นการประมาณคร่าวๆ แต่สิ่งต่าง ๆ อาจช้าลงหากแคช / หน่วยความจำ / สิ่งใดก็ตามที่เต็มไปด้วย / มากเกินไป

1
ขอบคุณมาร์ค ทำงานได้ยอดเยี่ยม ยิ่งเร็วขึ้นจากนั้นเรียกคืนจากการถ่ายโอนข้อมูล ใช้เวลาประมาณ 5 ชั่วโมง
ineersa

5

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

แต่วิธีการที่รู้จักกันดีสำหรับการเปลี่ยนแปลงออนไลน์เป็นตารางใหญ่คือPT-ออนไลน์คีมาเปลี่ยน มุมมองแบบง่าย ๆ ของสิ่งที่เครื่องมือนี้คัดลอกมาจากเอกสาร:

pt-online-schema-change ทำงานโดยสร้างสำเนาว่างของตารางเพื่อแก้ไขปรับเปลี่ยนตามที่ต้องการแล้วคัดลอกแถวจากตารางต้นฉบับไปยังตารางใหม่ เมื่อการคัดลอกเสร็จสิ้นมันจะย้ายตารางต้นฉบับและแทนที่ด้วยตารางใหม่ โดยค่าเริ่มต้นมันยังลดลงตารางเดิม

วิธีนี้อาจใช้เวลาสักครู่จึงจะเสร็จสมบูรณ์ แต่ในระหว่างกระบวนการตารางต้นฉบับจะใช้งานได้อย่างสมบูรณ์


ฉันจะลองโหลดจำนวนมากในคืนนี้ ถ้ามันไม่ทำงานจะต้องใช้เครื่องมือนี้ ข้อผิดพลาดเกิดจาก inetifieng สัญลักษณ์บางอย่างหลังจากใช้ sed เป็นคำสั่ง ยกตัวอย่างเช่นจะทำให้เกิดข้อผิดพลาด'D\'agostini' unknown command '\''แต่ไม่เสมอไปเช่นใน 30% ของกรณี นั่นเป็นเรื่องที่แปลกและบั๊กกี้ กันมาแม้กับทิ้ง hex- หยด ขอบคุณดีเร็ก
ineersa

4

alter table add column, algorithm=inplace, lock=none จะแก้ไขตาราง MySQL 5.6 โดยไม่คัดลอกตารางและไม่มีผลกระทบการล็อค

เพิ่งทดสอบเมื่อวานนี้มวลใส่แถว 70K ลงในตารางพาร์ติชั่น 280K แถว 7, 10K แถวในแต่ละพาร์ติชั่นโดยมีเวลาพัก 5 วินาทีเพื่อให้ปริมาณงานอื่น ๆ

เริ่มการแทรกจำนวนมากจากนั้นในเซสชั่นที่แยกต่างหากเริ่มalterคำสั่งออนไลน์ข้างต้นใน MySQL Workbench alterเสร็จก่อนการแทรกสองคอลัมน์ใหม่ถูกเพิ่มและไม่มีแถวที่เกิดจากการเปลี่ยนแปลงหมายถึง MySQL ไม่ได้คัดลอกแถวใด ๆ


1
ทำไมคำตอบนี้ไม่ได้รับการโหวตมากขึ้น? มันไม่ทำงาน?
fguillen

1

ปัจจุบันตัวเลือกที่ดีที่สุดสำหรับการแก้ไขตารางขนาดใหญ่น่าจะเป็นhttps://github.com/github/gh-ost

gh-ost เป็นโซลูชั่นการโอนย้ายสคีมาออนไลน์ที่ไม่ จำกัด สำหรับ MySQL มันสามารถทดสอบได้และให้ความน่าเชื่อถือ, การควบคุมแบบไดนามิก / การกำหนดค่าใหม่, การตรวจสอบ, และ perks การดำเนินงานจำนวนมาก

gh-ost สร้างเวิร์กโหลดที่เบาบนต้นแบบตลอดการย้ายข้อมูลแยกจากเวิร์กโหลดที่มีอยู่บนตารางที่ย้ายข้อมูล

มันได้รับการออกแบบบนพื้นฐานของประสบการณ์กับโซลูชั่นที่มีอยู่และเปลี่ยนกระบวนทัศน์ของการย้ายตาราง


1

ฉันคิดว่าMydumper / Myloaderเป็นเครื่องมือที่ดีสำหรับการดำเนินการเช่นนี้: เริ่มดีขึ้นทุกวัน คุณสามารถใช้ซีพียูของคุณและสามารถโหลดข้อมูลในแบบคู่ขนาน: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and-- การใช้งาน-/ คุณสมบัติ

ฉันจัดการเพื่อโหลดตาราง MySQL หลายร้อยกิกะไบต์ในไม่กี่ชั่วโมง

ตอนนี้เมื่อมันมาถึงการเพิ่มคอลัมน์ใหม่มันเป็นเรื่องยากที่ MySQL จะคัดลอกตารางทั้งหมดไปยังTMPพื้นที่หน่วยความจำด้วยALTER TABLE...แม้ว่า MySQL 5.6 จะบอกว่ามันสามารถทำการเปลี่ยนแปลงสคีมาออนไลน์ได้ แต่ฉันก็ยังไม่สามารถจัดการพวกมันได้ทางออนไลน์สำหรับตารางขนาดใหญ่ การโต้แย้งเป็นยัง


-2

ฉันเพิ่งมีปัญหาเดียวกัน วิธีแก้ปัญหาเล็กน้อย:

สร้างตาราง new_table SELECT * จาก oldtable;

ลบจาก new_table

แก้ไขตาราง new_table เพิ่มคอลัมน์ new_column int (11);

INSERT INTO new_table เลือก *, 0 จาก old_table

วางตาราง old_table; เปลี่ยนชื่อตาราง new_table เป็น old_table;


ทำไมไม่เพียงเพิ่มส่วนคำสั่ง where ในคำสั่งสร้างตารางเพื่อที่จะไม่เลือกข้อมูลใด ๆ การตัดทอนตารางจะมีประสิทธิภาพมากขึ้นแล้วจึงลบข้อมูล
Joe W

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