คุณจะลบการกระจายตัวของข้อมูลจากตาราง InnoDB ได้อย่างไร


13

ฉันมีฐานข้อมูลที่มีจำนวนตาราง

ฉันต้องการลบบางระเบียนออกจากตารางว่าไม่มีระเบียนมากกว่า 20K หรือ 50K

ตารางทั้งหมดเป็น InnoDB และfile_per_tableเป็นปิด

เมื่อฉันจะลบระเบียนจากตารางจำนวนหนึ่งจะมีการกระจายตัวในตาราง

มีวิธีใดที่จะกำจัดการแตกแฟรกเมนต์

อัพเดทเมื่อวันที่ 17 เมษายน

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

ดังนั้นตอนนี้คำถามของฉันคือฉันจะตัดสินใจได้อย่างไรว่าตารางของฉันมีการแยกส่วนหรือไม่



1
และบทความInnoDB: ดูแลการกระจายตัวของเว็บไซต์บล็อกของ Percona
ypercubeᵀᴹ

คำตอบ:


14

ฉันได้รับการแก้ไขใน StackOverflow กลับมาในเดือนตุลาคม 2010

โปรดจำไว้ว่าไฟล์ที่คึกคักที่สุดในโครงสร้างพื้นฐาน InnoDB: / var / lib / mysql / ibdata1

ไฟล์นี้เป็นที่เก็บข้อมูลสี่ประเภท

  • ข้อมูลตาราง
  • ดัชนีตาราง
  • ข้อมูล MVCC (การควบคุมการทำงานพร้อมกันหลายรายการ)
  • ตารางข้อมูลเมตา (รายการของ tablespace IDs)

การรันOPTIMIZE TABLEกับตาราง InnoDB ที่จัดเก็บใน ibdata1 ทำสองสิ่ง:

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

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

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

1) MySQLDump ฐานข้อมูลทั้งหมดลงในไฟล์ข้อความ SQL (เรียกว่า /root/SQLData.sql)

2) ดร็อปฐานข้อมูลทั้งหมด (ยกเว้นสคีมา mysql)

3) ปิด mysql

4) เพิ่มบรรทัดต่อไปนี้ใน /etc/my.cnf

[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

5) ลบ ibdata1, ib_logfile0 และ ib_logfile1

ณ จุดนี้ควรมี schema mysql ใน / var / lib / mysql เท่านั้น

6) เริ่ม mysql ใหม่

สิ่งนี้จะสร้าง ibdata1 ที่ 10 หรือ 18MB (ขึ้นอยู่กับรุ่นของ MySQL), ib_logfile0 และ ib_logfile1 ที่ 1G

7) โหลด /root/SQLData.sql ไปที่ mysql ใหม่

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

  • จำนวนมากของ DDL ( CREATE TABLE, DROP TABLE, ALTER TABLE)
  • การทำธุรกรรมจำนวนมาก
  • มีการเปลี่ยนแปลงมากมายที่จะส่งมอบต่อธุรกรรม

แต่ละตาราง InnoDB จะมีอยู่นอก ibdata1

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

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

ibdata1 จะไม่มีข้อมูล InnoDB และดัชนีอีกต่อไป

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

ฉันทำมาแล้วหลายครั้งในอาชีพการงานของฉันในฐานะ MySQL DBA

ในความเป็นจริงครั้งแรกที่ฉันทำสิ่งนี้ฉันยุบไฟล์ 50GB ibdata1 เป็น 500MB

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

อัพเดท 2012-04-19 09:23 EDT

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

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

คุณจะต้องดึงตัวเลขสองตัว

ไฟล์จากระบบปฏิบัติการ: คุณสามารถตรวจสอบขนาดไฟล์จากระบบปฏิบัติการเช่นนี้

ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'

FILESIZE จาก INFORMATION_SCHEMA: คุณสามารถตรวจสอบขนาดไฟล์จาก information_schema.tables ดังนี้:

SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';

เพียงลบค่า Information_SCHEMA จากค่าระบบปฏิบัติการแล้วหารด้วยส่วนแตกต่างด้วยค่า Information_SCHEMA

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

OPTIMIZE TABLE mydb.mytable;

หรือ

ALTER TABLE mydb.mytable ENGINE=InnoDB;

ฉันไม่คิดว่า / var / lib / mysql / ibdata1 ไม่ว่างถ้าคุณใช้ innodb_file_per_table = ตัวเลือกที่แนะนำ = 1
CrackerJack9

1
@ CrackerJack9 ibdata1 เป็น superbusy อย่างไม่น่าเชื่อเพราะสิ่งที่จะเข้าไป: 1) ข้อมูลบัฟเฟอร์การเขียนสองครั้ง 2) แทรกบัฟเฟอร์สำหรับดัชนีรอง 3) พจนานุกรมข้อมูล 4) ส่วนย้อนกลับ 5) เลิกทำตาราง โปรดข้ามไปscribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawingเพื่อแสดงภาพสิ่งเหล่านี้ แม้จะมีการลบข้อมูลและหน้าดัชนีสำหรับตาราง InnoDB แต่ ibdata1 ยังสามารถเติบโตได้อย่างมากในสภาพแวดล้อมการทำธุรกรรมสูง
RolandoMySQLDBA

1
@ CrackerJack9 ฉันมีโพสต์เพิ่มเติมที่พูดถึงกิจกรรมเพิ่มเติมเกี่ยวกับ ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA

ฉันไม่ได้ตระหนักว่ามันยังคงใช้งานอย่างหนัก ชื่นชมอย่างมาก!
CrackerJack9

@RolandoMySQLDBA คุณสามารถป๊อปอัพที่ Heap เมื่อคุณมีเวลาได้ไหม?
ypercubeᵀᴹ

5

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

หากคุณไม่ได้ใช้innodb_file_per_tableตัวเลือกสิ่งเดียวที่คุณทำได้คือส่งออกและนำเข้าฐานข้อมูลขั้นตอนที่ต้องใช้เวลาและดิสก์

แต่ถ้าคุณใช้innodb_file_per_tableคุณสามารถระบุและเรียกคืนพื้นที่นี้!

ก่อนหน้า 5.1.21 ตัวนับพื้นที่ว่างมีอยู่ในคอลัมน์ table_comment ของ information_schema.tables นี่คือ SQL บางตัวที่จะระบุตารางที่มีพื้นที่ว่างอย่างน้อย 100M (จริง ๆ แล้ว 97.65M):

เลือก table_schema, table_name, table_comment จาก data_schema.tables
WHERE ENGINE LIKE 'InnoDB' และ table_comment RLIKE 'InnoDB ฟรี: ([0-9] {6,}). *';

เริ่มต้นด้วย 5.1.21 นี่ถูกย้ายไปยังคอลัมน์ data_free (สถานที่ที่เหมาะสมกว่า):

เลือก table_schema, table_name, data_free / 1024/1024 AS data_free_MB จาก data_schema.tables WHERE ENGINE LIKE 'InnoDB' และ data_free> 100 * 1024 * 1024;

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

ALTER TABLE `TableName` ENGINE=InnoDB;

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


อีกสิ่งหนึ่งที่ฉันไม่สามารถเข้าใจความหมายของ data_free> 100 * 1024 * 1024 .. และเมื่อฉันเห็นผลลัพธ์ฉันไม่สามารถตัดสินใจว่าตารางนั้นมีการแยกส่วนหรือไม่ .. มีวิธีใดที่ฉัน สามารถพูดว่าตารางมีการแยกส่วนหรือไม่แยกส่วน?
Abdul Manaf

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