Howto: ทำความสะอาดเอ็นจินการจัดเก็บ mysql InnoDB หรือไม่


134

เป็นไปได้หรือไม่ที่จะทำความสะอาดเอ็นจินการจัดเก็บ mysql innodb จึงไม่ได้จัดเก็บข้อมูลจากตารางที่ถูกลบ

หรือฉันต้องสร้างฐานข้อมูลใหม่ทุกครั้ง?


อะไรทำให้คุณคิดว่า MySQL กำลังจัดเก็บข้อมูลจากตารางที่ถูกลบ
Robert Munteanu

1
ถ้าฉันวางตารางขนาดใหญ่ลงไปทั้งหมดไฟล์จัดเก็บข้อมูล InnoDB ของฉันจะไม่หดตัว
Bryan Field

คำตอบ:


352

นี่คือคำตอบที่สมบูรณ์ยิ่งขึ้นเกี่ยวกับ InnoDB เป็นกระบวนการที่ค่อนข้างยาว แต่คุ้มค่ากับความพยายาม

โปรดทราบว่า/var/lib/mysql/ibdata1เป็นไฟล์ที่ยุ่งที่สุดในโครงสร้างพื้นฐาน InnoDB โดยปกติจะมีข้อมูลหกประเภท:

  • ข้อมูลตาราง
  • ดัชนีตาราง
  • MVCC (Multiversioning Concurrency Control)ข้อมูล
    • กลุ่มย้อนกลับ
    • เลิกทำ Space
  • ข้อมูลเมตาของตาราง (พจนานุกรมข้อมูล)
  • Double Write Buffer (การเขียนพื้นหลังเพื่อป้องกันการพึ่งพา OS caching)
  • แทรกบัฟเฟอร์ (จัดการการเปลี่ยนแปลงดัชนีรองที่ไม่ซ้ำกัน)
  • ดูไฟล์ Pictorial Representation of ibdata1

สถาปัตยกรรม InnoDB

สถาปัตยกรรม InnoDB

หลายคนสร้างibdataไฟล์หลายไฟล์โดยหวังว่าจะมีการจัดการพื้นที่ดิสก์และประสิทธิภาพที่ดีขึ้นอย่างไรก็ตามความเชื่อนั้นผิดพลาด

วิ่งได้OPTIMIZE TABLEไหม?

น่าเสียดายที่การรันOPTIMIZE TABLEกับตาราง InnoDB ที่เก็บไว้ในไฟล์พื้นที่ตารางที่ใช้ร่วมกันibdata1ทำสองสิ่ง:

  • ทำให้ข้อมูลและดัชนีของตารางติดกันภายใน ibdata1
  • ทำให้ibdata1เติบโตขึ้นเนื่องจากข้อมูลที่ต่อเนื่องกันและหน้าดัชนีถูกผนวกเข้ากับibdata1

อย่างไรก็ตามคุณสามารถแยกข้อมูลตารางและดัชนีตารางออกจากกันibdata1และจัดการได้อย่างอิสระ

วิ่งOPTIMIZE TABLEด้วยได้innodb_file_per_tableไหม

สมมติว่าคุณกำลังจะเพิ่มไปinnodb_file_per_table /etc/my.cnf (my.ini)จากนั้นคุณสามารถรันOPTIMIZE TABLEบน InnoDB Tables ทั้งหมดได้หรือไม่?

ข่าวดี : เมื่อคุณเรียกใช้OPTIMIZE TABLEโดยinnodb_file_per_tableเปิดใช้งานสิ่งนี้จะสร้าง.ibdไฟล์สำหรับตารางนั้น ตัวอย่างเช่นหากคุณมีตารางที่มีmydb.mytableดาต้าเดอ/var/lib/mysqlร์ก็จะสร้างสิ่งต่อไปนี้

  • /var/lib/mysql/mydb/mytable.frm
  • /var/lib/mysql/mydb/mytable.ibd

.ibdจะมีหน้าข้อมูลและหน้าดัชนีสำหรับตารางที่ เยี่ยมมาก

ข่าวร้าย : สิ่งที่คุณต้องทำคือการดึงหน้าและดัชนีหน้าข้อมูลจากการใช้ชีวิตในmydb.mytable ibdataรายการพจนานุกรมข้อมูลสำหรับทุกตารางรวมถึงmydb.mytableยังคงอยู่ในพจนานุกรมข้อมูล (ดูภาพแทนของ ibdata1 ) คุณไม่สามารถลบเพียงแค่ibdata1จุดนี้ !!! โปรดทราบibdata1ว่าไม่ได้หดเลย

การล้างข้อมูลโครงสร้างพื้นฐาน InnoDB

ในการย่อขนาดibdata1ครั้งเดียวคุณต้องทำสิ่งต่อไปนี้:

  1. ถ่ายโอนข้อมูล (เช่นกับmysqldump) ฐานข้อมูลทั้งหมดลงใน.sqlไฟล์ข้อความ ( SQLData.sqlใช้ด้านล่าง)

  2. ทิ้งฐานข้อมูลทั้งหมด (ยกเว้นmysqlและinformation_schema) CAVEAT : เพื่อเป็นการป้องกันไว้ก่อนโปรดเรียกใช้สคริปต์นี้เพื่อให้แน่ใจว่าคุณได้รับสิทธิ์ผู้ใช้ทั้งหมด:

    mkdir /var/lib/mysql_grants
    cp /var/lib/mysql/mysql/* /var/lib/mysql_grants/.
    chown -R mysql:mysql /var/lib/mysql_grants
    
  3. เข้าสู่ระบบ mysql และเรียกใช้SET GLOBAL innodb_fast_shutdown = 0;(สิ่งนี้จะล้างการเปลี่ยนแปลงธุรกรรมที่เหลือทั้งหมดจากib_logfile0และib_logfile1)

  4. ปิดระบบ MySQL

  5. เพิ่มบรรทัดต่อไปนี้ใน/etc/my.cnf(หรือmy.iniบน Windows)

    [mysqld]
    innodb_file_per_table
    innodb_flush_method=O_DIRECT
    innodb_log_file_size=1G
    innodb_buffer_pool_size=4G
    

    (Sidenote: ไม่ว่าคุณจะตั้งค่าอะไรก็ตามinnodb_buffer_pool_sizeให้แน่ใจว่าinnodb_log_file_sizeเป็น 25% ของinnodb_buffer_pool_size.

    นอกจากนี้: innodb_flush_method=O_DIRECTไม่มีใน Windows)

  6. ลบibdata*และib_logfile*เลือกคุณสามารถลบโฟลเดอร์ทั้งหมดในยกเว้น/var/lib/mysql/var/lib/mysql/mysql

  7. เริ่ม MySQL (ซึ่งจะสร้างใหม่ibdata1[10MB ตามค่าเริ่มต้น] ib_logfile0และib_logfile1ที่ 1G ต่ออัน)

  8. นำเข้า SQLData.sql

ตอนนี้ibdata1จะยังคงเติบโต แต่เพียงประกอบด้วยข้อมูลเมตาตารางเพราะแต่ละตาราง InnoDB ibdata1จะอยู่ด้านนอกของ ibdata1จะไม่มีข้อมูล InnoDB และดัชนีสำหรับตารางอื่น ๆ อีกต่อไป

ตัวอย่างเช่นสมมติว่าคุณมีตาราง InnoDB mydb.mytableชื่อ หากคุณมองเข้าไป/var/lib/mysql/mydbคุณจะเห็นไฟล์สองไฟล์ที่แสดงถึงตาราง:

  • mytable.frm (ส่วนหัวของเครื่องมือจัดเก็บข้อมูล)
  • mytable.ibd (ข้อมูลตารางและดัชนี)

ด้วยinnodb_file_per_tableตัวเลือกใน/etc/my.cnfคุณสามารถเรียกใช้OPTIMIZE TABLE mydb.mytableและไฟล์/var/lib/mysql/mydb/mytable.ibdจะหดตัวลง

ฉันทำสิ่งนี้หลายครั้งในอาชีพการทำงานของฉันในฐานะ MySQL DBA ในความเป็นจริงครั้งแรกที่ฉันทำสิ่งนี้ฉันลดขนาดไฟล์50GB ibdata1ลงเหลือเพียง 500MB!

ให้มันลอง. หากคุณมีคำถามเพิ่มเติมเกี่ยวกับเรื่องนี้เพียงแค่ถาม เชื่อฉัน; สิ่งนี้จะใช้ได้ผลในระยะสั้นและในระยะยาว

ข้อแม้

ในขั้นตอนที่ 6 หาก mysql ไม่สามารถรีสตาร์ทได้เนื่องจากmysqlสคีมาเริ่มหลุดให้ย้อนกลับไปที่ขั้นตอนที่ 2 คุณได้สร้างสำเนาทางกายภาพของmysqlสคีมา คุณสามารถกู้คืนได้ดังนี้:

mkdir /var/lib/mysql/mysql
cp /var/lib/mysql_grants/* /var/lib/mysql/mysql
chown -R mysql:mysql /var/lib/mysql/mysql

กลับไปที่ขั้นตอนที่ 6 และดำเนินการต่อ

อัปเดต 2013-06-04 11:13 EDT

สำหรับการตั้งค่าinnodb_log_file_sizeเป็น 25% ของinnodb_buffer_pool_sizeในขั้นตอนที่ 5 นั้นกฎแบบครอบคลุมค่อนข้างเป็นโรงเรียนเก่า

ย้อนกลับไปในJuly 03, 2006, Percona มีบทความที่ดีว่าทำไมการเลือก innodb_log_file_size ต่อมาเมื่อวันNov 21, 2008, Percona ตามมาด้วยบทความอื่นในวิธีการคำนวณขนาดที่เหมาะสมขึ้นอยู่กับปริมาณงานที่ยอดการรักษามูลค่าหนึ่งชั่วโมงของการเปลี่ยนแปลง

ฉันได้เขียนโพสต์ใน DBA StackExchange เกี่ยวกับการคำนวณขนาดบันทึกและตำแหน่งที่ฉันอ้างถึงบทความ Percona ทั้งสองนี้

โดยส่วนตัวฉันจะยังคงใช้กฎ 25% สำหรับการตั้งค่าเริ่มต้น จากนั้นเนื่องจากสามารถกำหนดปริมาณงานได้แม่นยำยิ่งขึ้นเมื่อเวลาผ่านไปในการผลิตคุณสามารถปรับขนาดบันทึกระหว่างรอบการบำรุงรักษาได้ในเวลาเพียงไม่กี่นาที


9
ฉันยังใช้ตัวเลือก innodb_file_per_table เพื่อเอฟเฟกต์ที่ยอดเยี่ยมด้วยการมี 200 ฐานข้อมูลกับ 200 ตารางต่อเซิร์ฟเวอร์เดียวฉันสามารถเชื่อมโยงฐานข้อมูลความแตกต่างไปยังพาร์ติชันที่แตกต่างกันได้ดังนั้นจึงใช้บัฟเฟอร์ IO และสปินเดิลเพิ่มเติมที่จะมีให้ใช้ :)
Dave Rix

2
@SeanDowney BTW อย่าลืมเพิ่มinnodb_open_tablesถ้าจำเป็น ค่าเริ่มต้นคือ 300
RolandoMySQLDBA

2
@ giorgio79 คุณต้องตั้งค่าเม็ดมีดจำนวนมากให้มีค่ามากขึ้น นี่คือจุดที่ดี ฉันจะเพิ่มสาระสำคัญของคำถามของคุณในคำตอบของฉัน
RolandoMySQLDBA

3
ในระบบ 32 บิตไม่อนุญาตให้ใช้ค่า 4Gb สำหรับinnodb_buffer_pool_size Mysql จะเริ่มต้นอย่างเงียบ ๆ โดยปิดการใช้งาน innodb และตารางที่คืนค่าจะเปลี่ยนเป็น myisam ใช้ค่าที่น้อยกว่าเล็กน้อยเพื่อแก้ไข
เดวิด

5
พระเจ้าที่ดี. ฉันแค่อยากจะบอกว่านี่อาจเป็นหนึ่งในคำตอบที่ดีที่สุดที่ฉันเคยเห็นใน SO Damn fine job, Sir ช่วยฉันหาวิธีแก้ปัญหาของฉันเมื่อฉันได้รับ ERROR 2013 (HY000) เมื่อนำเข้า 154g db ขอบคุณสำหรับคำตอบที่ยอดเยี่ยม!
Josh Brown

4

โปรแกรม InnoDB ไม่จัดเก็บข้อมูลที่ถูกลบ เมื่อคุณแทรกและลบแถวพื้นที่ที่ไม่ได้ใช้จะถูกจัดสรรไว้ภายในไฟล์หน่วยเก็บข้อมูล InnoDB เมื่อเวลาผ่านไปพื้นที่โดยรวมจะไม่ลดลง แต่เมื่อเวลาผ่านไปพื้นที่ 'ลบและว่าง' จะถูกใช้ซ้ำโดยอัตโนมัติโดยเซิร์ฟเวอร์ DB

คุณสามารถปรับแต่งและจัดการพื้นที่ที่เครื่องยนต์ใช้เพิ่มเติมได้ผ่านการ re-org ของตารางด้วยตนเอง ในการดำเนินการนี้ให้ถ่ายโอนข้อมูลในตารางที่ได้รับผลกระทบโดยใช้ mysqldump วางตารางรีสตาร์ทบริการ mysql จากนั้นสร้างตารางใหม่จากไฟล์ดัมพ์

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