Việc tạo chỉ mục MySQL không thành công trên bàn là đầy đủ


10

CẬP NHẬT: tl; dr: Vấn đề là MySQL sử dụng TMPDIRkhi tạo chỉ mục. Và tôi TMPDIRlà người hết dung lượng đĩa.

Q gốc:

Tôi đang cố gắng thêm một chỉ mục vào bảng InnoDB và nhận được một table is full error. Tôi có đủ dung lượng đĩa và cấu hình MySQL có tệp trên mỗi bảng = 1. Dữ liệu bảng là 85 GB và tôi cho rằng chỉ số sẽ vào khoảng 20 GB - 30 GB và tôi có nhiều dung lượng đĩa hơn thế. Tôi cũng đang sử dụng ext3 vì vậy tôi không cảm thấy có vấn đề gì với giới hạn kích thước tệp theo quan điểm của HĐH.

Lỗi đăng nhập trông như thế này:

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

Điều gì gây ra điều này và làm thế nào tôi có thể giải quyết?

Bảng tạo:

`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`

Dữ liệu là 87,4GB và tôi ước tính có khoảng 1,5B hàng.

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: Kiểm tra xem các tệp hỗ trợ hệ điều hành và hệ thống tệp của bạn có kích thước này. InnoDB: Kiểm tra xem đĩa có đầy không hoặc vượt quá hạn ngạch đĩa." - bạn đã kiểm tra chưa? Bạn đang sử dụng ext2? ext3? xfs? Đã kiểm tra hạn ngạch cho người dùng?
Philᵀᴹ

@Phil Đã kiểm tra cả. Tôi đang sử dụng ext3 và gần như tích cực không có vấn đề gì với không gian đĩa. Linh cảm là nó có một cái gì đó để làm với một bản ghi đạt đến giới hạn của mình hoặc một cái gì đó, nhưng không có ý tưởng thực sự làm thế nào để xác minh và sửa chữa.
Noam

Tôi tự hỏi tập tin "(hợp nhất)" là gì?
akuzminsky

@akuzminsky hmm Mình không có ý kiến. Tôi chỉ chạy một tạo chỉ mục mới từ PHPMyAdmin.
Noam

+1 cho TMPDIR, đó cũng là vấn đề trên máy chủ của tôi.
Chad E.

Câu trả lời:


8

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

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 Fulltì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_oldtrong 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 exceededkhô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à ở tmpdirvị trí. Nếu /var/lib/mysqltmpkhô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/mysqltmpvà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/mysqlcó 100G trở lên miễn phí


Tôi đã mất nhiều tuần để xây dựng bảng ở vị trí đầu tiên từ bãi chứa (dữ liệu 85GB). Có cách nào khác ngoài việc làm lại từ đầu không? Bạn có thể đề nghị có thể phân vùng bảng?
Noam

Phân vùng sẽ không giúp ích vì ALTER TABLE để thêm chỉ mục vẫn sẽ cố tải mọi thứ trong một giao dịch. Hãy nhớ rằng, bạn đang chiến đấu với Kiến trúc InnoDB chứ không phải không gian đĩa. Câu trả lời của tôi sẽ giúp bạn trong trường hợp này vì mysqldump tiêm vài nghìn hàng cho mỗi INSERT, không phải là tất cả hoặc không có gì chèn vào bảng tạm thời với khả năng quay ngược lại.
RolandoMySQLDBA

Nhưng tạo bảng này sẽ (một lần nữa) sẽ mất mãi mãi. Bất kỳ cách nào để chạy một chỉ mục tạo trong khi vô hiệu hóa tùy chọn rollback?
Noam

Tạo một chỉ mục là DDL chứ không phải DML. Bạn không thể thay đổi hành vi DDL. Đó là lý do tại sao bài viết của tôi sử dụng các kỹ thuật DML.
RolandoMySQLDBA

Bảng có bao nhiêu hàng?
RolandoMySQLDBA
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.