Xin đừng bị lừa bởi thông báo lỗi The table 'my_table' is full
. Kịch bản hiếm gặp này hoàn toàn không có gì để làm với không gian đĩa. Điều kiện đầy đủ của bảng này phải được thực hiện với hệ thống ống nước bên trong của InnoDB.
Trước tiên, hãy xem sơ đồ này của Kiến trúc InnoDB
Xin lưu ý rằng không gian bảng hệ thống (tệp ibdata) chỉ có 128 Phân đoạn rollback và 1023 Slots Rollback mỗi phân đoạn rollback. Điều này đặt giới hạn về kích thước khả năng phục hồi của giao dịch. Nói cách khác, nếu một phân đoạn rollback duy nhất cần nhiều hơn 1023 vị trí để hỗ trợ giao dịch, giao dịch sẽ đạt table is full
điều kiện đó .
Hãy nghĩ về nhà hàng Tôm hùm đỏ ở New Jersey . Nó có thể có sức chứa 200 người. Nếu nhà hàng đã đầy, một dòng người có thể ra ngoài để chờ đợi. Nếu những người trên đường không kiên nhẫn, họ có thể rời đi vì nhà hàng đã đầy. Rõ ràng, giải pháp sẽ không làm cho New Jersey lớn hơn (hoặc có thêm không gian đĩa). Giải pháp sẽ là làm cho nhà hàng Red Lobster lớn hơn. Bằng cách đó, bạn có thể tăng sức chứa chỗ ngồi, giả sử, 240. Ngay cả với điều đó, một dòng có thể hình thành bên ngoài nếu hơn 240 người quyết định đến Red Lobster.
Chỉ để cho bạn một ví dụ, tôi đã có một máy khách với 2TB không gian bảng hệ thống và innodb_file_per_table đã bị vô hiệu hóa. (346G cho ibdata1, thiết lập lại cho ibdata2). Tôi đã chạy truy vấn này
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
Tiếp theo, tôi đã trừ InnoDBDataIndexSpace từ tổng số các tệp cho ibdata1 và ibdata2. Tôi có hai điều làm tôi sốc
- Có 106GB còn lại trong không gian bảng hệ thống.
- Tôi có
Table is Full
tình trạng tương tự
Điều này có nghĩa là 106GB đã được sử dụng cho hệ thống ống nước nội bộ của InnoDB. Khách hàng đang sử dụng ext3 tại thời điểm đó.
Giải pháp cho tôi là thêm ibdata3. Tôi đã thảo luận điều này trong bài viết cũ của tôi Làm thế nào để giải quyết "Bảng ... đã đầy" với "innodb_file_per_table"?
Tôi đã thảo luận về điều này trong các bài viết khác là tốt
Hãy nhớ rằng tình trạng này có thể xảy ra ngay cả khi innodb_file_per_table được bật. Làm sao? Rollback và Undo Logs là nguồn tăng đột biến không kiểm soát được là sự tăng trưởng cho ibdata1 .
CÂU HỎI THỰC TẾ CỦA BẠN
Vì bạn đang thêm một chỉ mục vào một bảng và nhận Table is Full
, nên bảng phải rất lớn và không thể nằm gọn trong một phân đoạn rollback duy nhất. Bạn phải làm như sau:
BƯỚC 01
Lấy dữ liệu vào một tệp kết xuất
mysqldump --no-create-info mydb mytable > table_data.sql
BƯỚC 02
Đăng nhập vào MySQL và chạy nó
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;
BƯỚC 03
Tải bảng với chỉ mục bổ sung với dữ liệu
mysql -Dmydb < table_data.sql
Đó là tất cả.
Hãy xem, vấn đề là ALTER TABLE sẽ cố gắng tiêm tất cả các hàng trong bảng lớn của bạn dưới dạng một giao dịch. Sử dụng mysqldump sẽ chèn dữ liệu vào bảng (hiện có chỉ mục mới) hàng nghìn hàng cùng một lúc, không phải tất cả các hàng trong một giao dịch.
Đừng lo lắng về what if this doesn't work?
Bảng gốc sẽ được đặt tên mytable_old
trong trường hợp có bất cứ điều gì. nó có thể phục vụ như một bản sao lưu. Bạn có thể bỏ bản sao lưu khi bạn biết bảng mới hoạt động cho bạn.
Hãy thử một lần !!!
CẬP NHẬT 2014-06-16 11:13 EDT
Nếu bạn lo lắng về việc kết xuất dữ liệu lớn hơn, chỉ cần gzip nó.
Bạn có thể làm các bước tương tự, nhưng như sau
BƯỚC 01
Lấy dữ liệu vào một tệp kết xuất
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
BƯỚC 02
Đăng nhập vào MySQL và chạy nó
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;
BƯỚC 03
Tải bảng với chỉ mục bổ sung với dữ liệu
gzip -d < table_data.sql.gz | mysql -Dmydb
hoặc là
gunzip < table_data.sql.gz | mysql -Dmydb
CẬP NHẬT 2014-06-16 12:55 EDT
Tôi chỉ nghĩ về một khía cạnh khác liên quan đến vấn đề này.
Vì bạn đang thực hiện DDL chứ không phải DML, có thể đây không phải là hệ thống ống nước nội bộ của InnoDB. Vì DDL không thể phục hồi cho InnoDB , vấn đề phải là hệ thống ống nước bên ngoài. Hệ thống ống nước bên ngoài này bị tắc ở đâu? Tôi nghi ngờ thư mục tạm thời cho hệ điều hành. Tại sao?
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
Thấy disk quota exceeded
không? Hạn ngạch đĩa này được áp đặt ở đâu?
Chạy truy vấn này
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Bạn nói đó là /var/lib/mysqltmp
Bây giờ, chạy cái này trong HĐH
df -h /var/lib/mysqltmp
Một cái gì đó cho tôi biết rằng không gian cho /var/lib/mysqltmp
đã hết. Sau tất cả, bạn chỉ có 14G miễn phí. Trong con mắt của DDL (để tạo chỉ mục), một sự phục hồi đã xảy ra, không phải trong tệp ibdata1, mà là ở tmpdir
vị trí. Nếu /var/lib/mysqltmp
không được gắn ở bất cứ đâu, thì dữ liệu tạm thời đang được ghi trong phân vùng gốc. Nếu /var/lib/mysqltmp
được gắn ở đâu đó, thì giá đỡ đó đang được lấp đầy với dữ liệu hàng. Trong cả hai trường hợp, không có đủ chỗ để hoàn thành DDL.
Bạn có hai lựa chọn ở đây
LỰA CHỌN 1
Bạn cũng có thể tạo một đĩa lớn (có thể có 100 + GB) và gắn /var/lib/mysqltmp
vào đĩa lớn đó.
LỰA CHỌN 2
Đề xuất 3 bước của tôi vẫn hoạt động, ngay cả với không gian đĩa hạn chế mà bạn có
NHẬN XÉT
Thật xấu hổ khi thông báo lỗi bạn đăng
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Điều này có nghĩa là hệ điều hành là tốt. Nó cũng không tồn tại bất kỳ số lỗi liên quan cho tình huống này.
Có một điều bạn nên biết. Tài liệu MySQL nói rằng Tạo chỉ mục nhanh cho InnoDB vẫn đi vào đĩa :
Trong quá trình tạo chỉ mục, các tệp được ghi vào thư mục tạm thời ($ TMPDIR trên Unix,% TEMP% trên Windows hoặc giá trị của biến cấu hình --tmpdir). Mỗi tệp tạm thời đủ lớn để chứa một cột tạo nên chỉ mục mới và mỗi cột được xóa ngay khi nó được hợp nhất vào chỉ mục cuối cùng.
Do hạn chế của MySQL, bảng được sao chép, thay vì sử dụng Chế độ tạo chỉ mục nhanh, khi bạn tạo một chỉ mục trên BẢNG TẠM THỜI. Điều này đã được báo cáo là Lỗi MySQL # 39833 .
CẬP NHẬT 2014-06-16 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Vui lòng đảm bảo /mnt/cbsvolume1/var/lib/mysql
có 100G trở lên miễn phí