Не обманюйте повідомлення про помилку The table 'my_table' is full
. Цей рідкісний сценарій абсолютно не має нічого спільного з дисковим простором. Ця повна умова таблиці стосується внутрішньої сантехніки InnoDB.
Спочатку погляньте на цю діаграму архітектури InnoDB
Зверніть увагу, що в системному просторі таблиць (файл ibdata) є лише 128 відкатних сегментів та 1023 відказових слотів за сегмент відкоту. Це встановлює обмеження на величину можливостей відката транзакції. Іншими словами, якщо одному сегменту відкату потрібно більше 1023 слотів для підтримки транзакції, транзакція вплине на цю table is full
умову.
Подумайте про ресторан Red Lobster в Нью-Джерсі . Він може мати 200 чоловік. Якщо ресторан переповнений, рядок людей може вийти на вулицю, щоб зачекати. Якщо люди на лінії будуть нетерплячі, вони можуть піти, оскільки ресторан переповнений. Очевидно, що рішення не було б зробити Нью-Джерсі більшим (або отримати більше дискового простору). Рішенням було б зробити ресторан Червоного Омару більшим. Таким чином ви можете збільшити кількість місць до, скажімо, до 240. Навіть при цьому лінія може формуватися зовні, якщо більше 240 людей вирішать приїхати до Червоного омарів.
Просто для прикладу, у мене був клієнт з 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. У мене дві речі мене шокували
- Всередині системного простору залишилось 106 Гб.
- У мене такий самий
Table is Full
стан
Це означає, що 106 Гб використовували для внутрішньої сантехніки InnoDB. Клієнт використовував ext3 у той час.
Для мене рішення було додати ibdata3. Я обговорював це в своїй старій публікації Як вирішити "Таблиця ... повна" за допомогою "innodb_file_per_table"?
Я обговорював це і в інших постах
Майте на увазі, що ця умова може статися, навіть якщо ввімкнено innodb_file_per_table . Як? Зворотні звороти та скасування журналів є джерелом неконтрольованих шипів - зростання для 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
Якщо ви турбуєтесь про скидання даних, яке є величезним, просто згорніть його.
Можна зробити ті ж дії, але наступним чином
КРОК 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 , проблемою має бути зовнішня сантехніка. Де ця зовнішня сантехніка забивається? Я підозрюю, що папка temp для ОС. Чому?
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
ніде не встановлено, то дані про темп записуються в кореневий розділ. Якщо /var/lib/mysqltmp
він встановлений десь, то це кріплення заповнюється даними про рядки. В будь-якому випадку недостатньо місця для заповнення DDL.
Тут у вас є два варіанти
ВАРІАНТ №1
Ви також можете створити великий диск (можливо, зі 100 + ГБ) та встановити /var/lib/mysqltmp
на цьому великому диску.
ВАРІАНТ №2
Мої 3-крокові пропозиції все одно повинні працювати, навіть якщо у вас є обмежений простір
КОМЕНТАР
Прикро повідомляє повідомлення про помилку, яке ви опублікували
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Це означає, що ОС просто чудова. Також для цієї ситуації не існує жодного асоційованого номера помилки.
Є ще одна річ, яку ви повинні знати. Документація MySQL говорить, що швидке створення індексу для InnoDB все ще йде на диск :
Під час створення індексу файли записуються у тимчасовий каталог ($ TMPDIR на Unix,% TEMP% у Windows або значення змінної конфігурації --tmpdir). Кожен тимчасовий файл достатньо великий, щоб вмістити один стовпець, який складається з нового індексу, і кожен видаляється, як тільки він об'єднується в кінцевий індекс.
Через обмеження MySQL таблиця скопіюється, а не використовує «Швидке створення індексу» під час створення індексу на ЧАСНОЇ ТАБЛИЦІ. Про це повідомляється як MySQL Bug # 39833 .
ОНОВЛЕННЯ 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 або більше