Невдале створення таблиці індексу MySQL на столі


10

UPDATE: tl; dr: Проблема полягала в тому, що MySQL використовує TMPDIRпри створенні індексів. І моєму TMPDIRне вистачало місця на диску.

Оригінальний Q:

Я намагаюся додати індекс до таблиці InnoDB і отримую table is full error. У мене достатньо місця на диску, і в конфігурації MySQL є файл на таблицю = 1. Дані таблиці - 85 Гб, і я припускаю, що індекс буде приблизно 20 ГБ - 30 ГБ, і у мене набагато більше місця на диску. Я також використовую 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,4 ГБ, і я вважаю, що є близько 1,5 В рядків.

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 і майже впевнений, що з дисковим простором не виникає проблем. Hunch - це щось пов’язане з тим, щоб журнал досяг його межі чи щось таке, але насправді не існує ідеї, як перевірити та виправити.
Ноам

Цікаво, що таке файл "(злиття)"?
akuzminsky

@akuzminsky hmm Я поняття не маю. Я запустив лише створення нового індексу від PHPMyAdmin.
Ноам

+1 для TMPDIR, це також було проблемою на моєму сервері.
Чад Е.

Відповіді:


8

Не обманюйте повідомлення про помилку The table 'my_table' is full. Цей рідкісний сценарій абсолютно не має нічого спільного з дисковим простором. Ця повна умова таблиці стосується внутрішньої сантехніки InnoDB.

Спочатку погляньте на цю діаграму архітектури 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 або більше


На те, щоб побудувати таблицю, перш за все, з демпінгу (85 ГБ даних) знадобилися тижні. Чи є інший спосіб, крім того, як це робити все заново? Чи рекомендуєте ви, можливо, розділити таблицю?
Ноам

Розділення не допоможе, оскільки ALTER TABLE для додавання індексу все ще намагатиметься завантажити все в одній транзакції. Пам'ятайте, ви боретеся з архітектурою InnoDB, а не з дисковим простором. Моя відповідь повинна допомогти вам у цьому випадку, оскільки mysqldump вводить кілька тисяч рядків за INSERT, а не вкладку, що містить усе або нічого, у таблицю темп із можливістю відката.
RolandoMySQLDBA

Але створення цієї таблиці займе (знову) вічно. Будь-який спосіб запустити індекс створення при відключенні опції відката?
Ноам

Створення індексу - це DDL, а не DML. Ви не можете змінити поведінку DDL. Тому моя публікація використовує методи DML.
RolandoMySQLDBA

BTW, скільки рядків має таблиця ???
RolandoMySQLDBA
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.