การสร้างดัชนี MySQL ล้มเหลวในตารางเต็ม


10

UPDATE: tl; dr: ปัญหาคือ MySQL ใช้TMPDIRเมื่อสร้างดัชนี และฉันTMPDIRก็เป็นหนึ่งในพื้นที่ดิสก์หมด

ต้นฉบับ Q:

ฉันพยายามที่จะเพิ่มดัชนีเพื่อตาราง InnoDB, table is full errorและได้รับการ ฉันมีพื้นที่ดิสก์เพียงพอและการตั้งค่า MySQL มีไฟล์ต่อตาราง = 1 ข้อมูลตารางคือ 85GB และฉันคิดว่าดัชนีจะอยู่ที่ประมาณ 20GB - 30GB และฉันมีพื้นที่ดิสก์มากกว่านั้น ฉันใช้ ext3 ด้วยดังนั้นฉันไม่รู้สึกว่ามีปัญหากับการ จำกัด ขนาดไฟล์จากมุมมองของระบบปฏิบัติการ

ข้อผิดพลาดที่บันทึกไว้มีลักษณะดังนี้:

140616 13:04:33  InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full

อะไรเป็นสาเหตุของปัญหานี้และฉันจะแก้ไขได้อย่างไร

สร้างตาราง:

`CREATE TABLE `my_table` (
 `uid_from` bigint(11) NOT NULL,
 `uid_to` bigint(11) NOT NULL,
 `counter` int(11) NOT NULL,
 `updated` date NOT NULL,
 PRIMARY KEY (`uid_to`,`uid_from`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`

ตามที่เป็นข้อมูลคือ 87.4GB และฉันประมาณว่ามีแถวประมาณ 1.5B

SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Variable_name   Value
tmpdir  /tmp

[root@web ~]# df -h /tmp
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       40G   24G   14G  64% /

1
"InnoDB: ตรวจสอบว่าระบบปฏิบัติการและระบบไฟล์ของคุณรองรับไฟล์ขนาดนี้ InnoDB: ตรวจสอบว่าดิสก์ไม่เต็มหรือมีโควต้าดิสก์เกิน" - คุณตรวจสอบแล้วหรือยัง คุณใช้ ext2 หรือไม่? ext3? XFS? ตรวจสอบโควต้าสำหรับผู้ใช้หรือไม่
Philᵀᴹ

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

ฉันสงสัยว่าไฟล์ "(ผสาน)" คืออะไร
akuzminsky

@akuzminsky hmm ฉันไม่มีความคิด ฉันรันการสร้างดัชนีใหม่จาก PHPMyAdmin เท่านั้น
Noam

+1 สำหรับ TMPDIR นั่นคือปัญหาบนเซิร์ฟเวอร์ของฉันเช่นกัน
ชาดอี.

คำตอบ:


8

The table 'my_table' is fullกรุณาอย่าหลงกลโดยข้อผิดพลาด สถานการณ์ที่หายากนี้ไม่มีอะไรเกี่ยวข้องกับดิสก์ ตารางนี้มีเงื่อนไขอย่างครบถ้วนเกี่ยวกับระบบประปาภายในของ InnoDB

ขั้นแรกให้ดูที่แผนภาพของสถาปัตยกรรม InnoDB นี้

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

โปรดทราบว่าพื้นที่ตารางระบบ (ไฟล์ ibdata) มีเพียง128 เซ็กเมนต์ย้อนกลับและ 1,023 สล็อตย้อนกลับต่อเซ็กเมนต์ย้อนกลับ สถานที่นี้ จำกัด ขนาดของความสามารถในการย้อนกลับของธุรกรรม กล่าวอีกนัยหนึ่งถ้าเซ็กเมนต์ย้อนกลับเดียวต้องการมากกว่า 1023 สล็อตเพื่อสนับสนุนธุรกรรมธุรกรรมจะเข้าสู่table is fullเงื่อนไขนั้น

คิดว่าร้านอาหาร Red Lobster ในรัฐนิวเจอร์ซีย์ อาจมีความจุ 200 คน หากร้านอาหารเต็มผู้คนอาจออกไปข้างนอกเพื่อรอ หากผู้คนในสายได้รับความอดทนพวกเขาอาจออกไปเพราะร้านอาหารเต็ม เห็นได้ชัดว่าการแก้ปัญหาจะไม่ทำให้ New Jersey ใหญ่ขึ้น (หรือเพิ่มพื้นที่ว่างมากขึ้น) ทางออกจะทำให้ร้านอาหาร Red Lobster ใหญ่ขึ้น ด้วยวิธีนี้คุณสามารถเพิ่มความจุที่นั่งเป็น 240 ได้แม้ว่าจะมีเส้นข้างนอกหากคนมากกว่า 240 คนตัดสินใจมาที่ Red Lobster

เพียงเพื่อให้คุณตัวอย่างฉันมีลูกค้าที่มี 2TB ของพื้นที่ตารางระบบและinnodb_file_per_tableถูกปิดการใช้งาน (346G สำหรับ ibdata1 การรีเซ็ตสำหรับ ibdata2) ฉันเรียกใช้แบบสอบถามนี้

SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';

ต่อไปฉันย่อส่วน InnoDBDataIndexSpace จากผลรวมของขนาดไฟล์สำหรับ ibdata1 และ ibdata2 ฉันได้สองสิ่งที่ทำให้ฉันตกใจ

  • มีพื้นที่เหลือ 106GB ในพื้นที่ตารางระบบ
  • ฉันได้รับTable is Fullเงื่อนไขเดียวกันนี้

นี่หมายความว่า 106GB ใช้สำหรับระบบประปาภายในของ InnoDB ลูกค้ากำลังใช้ ext3 ในเวลานั้น

ทางออกสำหรับฉันคือการเพิ่ม ibdata3 ฉันพูดถึงเรื่องนี้ในโพสต์เก่าของฉันวิธีแก้ปัญหา "ตาราง ... เต็ม" กับ "innodb_file_per_table"?

ฉันได้กล่าวถึงเรื่องนี้ในกระทู้อื่น ๆ เช่นกัน

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

คำถามจริงของคุณ

เนื่องจากคุณกำลังเพิ่มดัชนีลงในตารางและรับTable is Fullตารางจะต้องมีขนาดใหญ่และไม่สามารถอยู่ในส่วนย้อนกลับเดียวได้ คุณต้องทำสิ่งต่อไปนี้:

ขั้นตอนที่ 01

รับข้อมูลลงในไฟล์ดัมพ์

mysqldump --no-create-info mydb mytable > table_data.sql

ขั้นตอนที่ 02

เข้าสู่ระบบ MySQL และเรียกใช้สิ่งนี้

USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;

ขั้นตอนที่ 03

โหลดตารางพร้อมกับดัชนีเพิ่มเติมพร้อมข้อมูล

mysql -Dmydb < table_data.sql

นั่นคือทั้งหมดที่

ดูว่าปัญหาคือ ALTER TABLE จะพยายามแทรกแถวทั้งหมดในตารางขนาดใหญ่ของคุณเป็นธุรกรรมเดียว การใช้ mysqldump จะแทรกข้อมูลลงในตาราง (ตอนนี้มีดัชนีใหม่) หลายพันแถวพร้อมกันไม่ใช่ทุกแถวในธุรกรรมเดียว

ไม่ต้องกังวลเกี่ยวกับwhat if this doesn't work?ตารางต้นฉบับจะมีชื่อmytable_oldในกรณีที่มีอะไร สามารถใช้เป็นข้อมูลสำรองได้ คุณสามารถทำสำเนาสำรองเมื่อคุณรู้ว่าตารางใหม่นั้นเหมาะกับคุณ

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

อัพเดท 2014-06-16 11:13 EDT

หากคุณกังวลเกี่ยวกับการถ่ายโอนข้อมูลที่ใหญ่กว่าเดิมเพียงแค่ gzip

คุณสามารถทำตามขั้นตอนเดียวกัน แต่ดังต่อไปนี้

ขั้นตอนที่ 01

รับข้อมูลลงในไฟล์ดัมพ์

mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz

ขั้นตอนที่ 02

เข้าสู่ระบบ MySQL และเรียกใช้สิ่งนี้

USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;

ขั้นตอนที่ 03

โหลดตารางพร้อมกับดัชนีเพิ่มเติมพร้อมข้อมูล

gzip -d < table_data.sql.gz | mysql -Dmydb

หรือ

gunzip < table_data.sql.gz | mysql -Dmydb

อัปเดต 2014-06-16 12:55 EDT

ฉันแค่คิดถึงแง่มุมอื่นเกี่ยวกับปัญหานี้

เนื่องจากคุณกำลังทำ DDL และไม่ใช่ DML เป็นไปได้ว่านี่ไม่ใช่การประปาภายในของ InnoDB เนื่องจากDDL ไม่สามารถย้อนกลับสำหรับ InnoDBได้ปัญหาจึงต้องมีการประปาภายนอก ท่อประปาภายนอกนี้ถูกอุดตันอยู่ที่ไหน ฉันสงสัยว่าโฟลเดอร์ชั่วคราวสำหรับระบบปฏิบัติการ ทำไม?

140616 13:04:33  InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full

เห็นdisk quota exceededไหม โควต้าดิสก์นี้ถูกกำหนดไว้ที่ไหน

เรียกใช้แบบสอบถามนี้

SHOW GLOBAL VARIABLES LIKE 'tmpdir';

คุณบอกว่ามัน /var/lib/mysqltmp

ตอนนี้เรียกใช้สิ่งนี้ในระบบปฏิบัติการ

df -h /var/lib/mysqltmp

มีบางอย่างบอกฉันว่าพื้นที่สำหรับ/var/lib/mysqltmpหมดแล้วคุณมีฟรี 14G ในสายตาของ DDL (เพื่อสร้างดัชนี) การย้อนกลับเกิดขึ้นไม่ใช่ในไฟล์ ibdata1 แต่อยู่ในtmpdirตำแหน่ง หาก/var/lib/mysqltmpไม่ได้เมาต์ทุกที่ข้อมูล temp จะถูกเขียนในพาร์ติชันรูท หาก/var/lib/mysqltmpเมานต์ที่ใดที่หนึ่งแสดงว่าเมานท์นั้นเต็มไปด้วยข้อมูลแถว ในทั้งสองกรณีมีพื้นที่ไม่เพียงพอที่จะทำ DDL ให้เสร็จสมบูรณ์

คุณมีสองตัวเลือกที่นี่

ตัวเลือกที่ 1

คุณสามารถสร้างดิสก์ขนาดใหญ่ (อาจมี 100 + GB) และเชื่อม/var/lib/mysqltmpต่อกับดิสก์ขนาดใหญ่นั้น

OPTION # 2

คำแนะนำ 3 ขั้นตอนของฉันยังคงใช้ได้แม้จะมีพื้นที่ จำกัด ที่คุณมี

COMMENTARY

เป็นความอัปยศที่ข้อความแสดงข้อผิดพลาดที่คุณโพสต์แจ้งไว้

InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.

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

มีอีกสิ่งที่คุณควรรู้ เอกสาร MySQL บอกว่าการสร้างดัชนีอย่างรวดเร็วสำหรับ InnoDB ยังคงไปที่ดิสก์ :

ระหว่างการสร้างดัชนีไฟล์จะถูกเขียนไปยังไดเร็กทอรีชั่วคราว ($ TMPDIR บน Unix,% TEMP% บน Windows หรือค่าของ --tmpdir ตัวแปรการตั้งค่า) แต่ละไฟล์ชั่วคราวมีขนาดใหญ่พอที่จะเก็บหนึ่งคอลัมน์ที่สร้างดัชนีใหม่และแต่ละไฟล์จะถูกลบทันทีที่รวมเข้ากับดัชนีสุดท้าย

เนื่องจากข้อ จำกัด ของ MySQL ตารางจะถูกคัดลอกแทนที่จะใช้“ การสร้างดัชนีอย่างรวดเร็ว” เมื่อคุณสร้างดัชนีในตารางชั่วคราว นี้ได้รับรายงานว่าเป็นMySQL bug #

อัพเดท 2014-06-16 13:58 EDT

[mysqld]
datadir                         = /mnt/cbsvolume1/var/lib/mysql
tmpdir                          = /mnt/cbsvolume1/var/lib/mysql

โปรดตรวจสอบให้แน่ใจว่า/mnt/cbsvolume1/var/lib/mysqlมี 100G หรือมากกว่านั้นฟรี


ฉันใช้เวลาหลายสัปดาห์ในการสร้างตารางตั้งแต่แรกจากการถ่ายโอนข้อมูล (ข้อมูล 85GB) มีวิธีอื่นนอกเหนือจากการทำสิ่งนี้อีกครั้งหรือไม่? คุณจะแนะนำให้แบ่งพาร์ติชันตารางหรือไม่?
Noam

การแบ่งพาร์ติชันจะไม่ช่วยได้เนื่องจาก ALTER TABLE เพื่อเพิ่มดัชนีจะยังคงพยายามโหลดทุกอย่างในธุรกรรมเดียว จำไว้ว่าคุณกำลังต่อสู้กับสถาปัตยกรรม InnoDB ไม่ใช่พื้นที่ทำงาน คำตอบของฉันควรช่วยคุณในกรณีนี้เนื่องจาก mysqldump แทรกสองสามพันแถวต่อ INSERT ไม่ใช่การแทรกทั้งหมดหรือไม่มีอะไรลงในตารางชั่วคราวที่มีความเป็นไปได้ในการย้อนกลับ
RolandoMySQLDBA

แต่การสร้างตารางนี้จะใช้เวลาตลอดไป มีวิธีใดบ้างในการสร้างดัชนีในขณะที่ปิดใช้งานตัวเลือกการย้อนกลับ
Noam

การสร้างดัชนีคือ DDL ไม่ใช่ DML คุณไม่สามารถเปลี่ยนพฤติกรรม DDL นั่นเป็นเหตุผลที่โพสต์ของฉันใช้เทคนิค DML
RolandoMySQLDBA

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