Пожалуйста, не обманывайте себя сообщением об ошибке The table 'my_table' is full
. Этот редкий сценарий не имеет абсолютно никакого отношения к дисковому пространству. Это полное состояние таблицы связано с внутренней сантехникой InnoDB.
Во-первых, взгляните на эту диаграмму архитектуры InnoDB
Обратите внимание, что системное табличное пространство (файл ibdata) имеет только 128 сегментов отката и 1023 слота отката на сегмент отката. Это накладывает ограничения на размер отката транзакции. Другими словами, если одному сегменту отката требуется более 1023 слотов для поддержки транзакции, транзакция выполнит это table is full
условие.
Вспомните ресторан Red Lobster в Нью-Джерси . Он может вместить 200 человек. Если ресторан переполнен, ряд людей может выйти на улицу, чтобы ждать. Если люди на линии нетерпеливы, они могут уйти, потому что ресторан переполнен. Очевидно, что решение не состояло бы в том, чтобы сделать Нью-Джерси больше (или получить больше дискового пространства). Решение было бы сделать ресторан Red Lobster больше. Таким образом, вы можете увеличить вместимость до, скажем, до 240. Даже при этом, линия может образоваться снаружи, если более 240 человек решат приехать в Красный Лобстер.
Просто чтобы дать вам пример, у меня был клиент с 2 ТБ системного табличного пространства, и 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 ПО ВОСТОЧНОМУ ВРЕМЕНИ
Я просто подумал о другом аспекте в этом вопросе.
Поскольку вы выполняете 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
нигде не монтируется, то временные данные записываются в корневой раздел. Если /var/lib/mysqltmp
где-то монтируется, то это монтирование заполняется данными строки. В любом случае недостаточно места для завершения DDL.
У вас есть два варианта здесь
ОПЦИЯ 1
Вы также можете создать большой диск (возможно, с объемом 100 ГБ) и смонтировать его /var/lib/mysqltmp
на этом большом диске.
ВАРИАНТ № 2
Мои трехэтапные предложения должны работать, даже если у вас ограниченное дисковое пространство
КОММЕНТАРИЙ
Обидно, что сообщение об ошибке, которое вы отправили, говорит
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Это означает, что ОС просто отлично. Также не существует никакого связанного номера ошибки для этой ситуации.
Есть еще одна вещь, которую вы должны знать. Документация MySQL говорит, что Быстрое Создание Индекса для InnoDB все еще идет на диск :
Во время создания индекса файлы записываются во временный каталог ($ TMPDIR в Unix,% TEMP% в Windows или значение переменной конфигурации --tmpdir). Каждый временный файл достаточно велик для размещения одного столбца, составляющего новый индекс, и каждый из них удаляется, как только он объединяется с окончательным индексом.
Из-за ограничений MySQL таблица копируется, вместо того, чтобы использовать «Быстрое создание индекса» при создании индекса в TEMPORARY TABLE. Это было сообщено как MySQL Bug # 39833 .
ОБНОВЛЕНИЕ 2014-06-16 13:58 ПО ВОСТОЧНОМУ ВРЕМЕНИ
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Пожалуйста, убедитесь, что /mnt/cbsvolume1/var/lib/mysql
100G или более бесплатно