Cайт веб-разработчика, программиста Ruby on Rails ESV Corp. Екатеринбург, Москва, Санкт-Петербург, Новосибирск, Первоуральск

Админка на Ruby on Rails

Ошибка MySQL InnoDB: Row size too large (> 8126)

При хранении в таблице MySQL InnoDB множества текстовых полей может возникнуть следующая ошибка (применительно к Ruby on Rails):

ActiveRecord::StatementInvalid (Mysql2::Error: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.

После поиска информации на эту тему, было выяснено, что данная ошибка возникает тогда, когда какая-либо строка таблицы не вмещается в половину страницы памяти, с которыми работает MySQL. Страницы эти равны 16 Кб, а половина, стало быть, 8 Кб.

Само по себе ограничение довольно странное, но на первый взгляд кажется трудно достижимым, ведь как известно, MySQL хранят текстовые данные в хранилище, отдельном от табличных строк. Оказалось, что это верно только на половину. На самом деле InnoDB хранит в отдельном хранилище только «излишки», к коим он не относит первые 768 байтов каждого текстового поля. Т.е. любой текст будет отъедать от длины строки столько байт, сколько он содержит, но не больше 768. Несложно подсчитать, что максимальное число текстовых полей длиной от 768 байт, которое можно безопасно хранить в одной таблице — 10. Но стоит увеличить количество полей хотя бы на одно, и мы получим ту же ошибку.

Больше всего поражает не абсурдность ограничения, и даже не «прожорливость» строковых типов данных, а умалчивание этой проблемы. InnoDB позволяет совершенно спокойно создавать таблицы с сотнями текстовых полей. При этом о том, что вы не сможете ими воспользоваться, вы узнаете только на продакшене при заполнении таблицы реальными данными. Невнятное сообщение об ошибке тоже оставляет мало положительных эмоций.

Решение проблемы состоит в использовании формата файлов Barracuda и изменение ROW_FORMAT у таблиц на DYNAMIC (или COMPRESSED). Или просто использование ROW_FORMAT=DYNAMIC. Работает в MySQL 5.5 и более поздних версиях.

1. в файле конфигурации my.cnf в разделе [mysqld] необходимо прописать следующие строки:

innodb_file_format = Barracuda
innodb_file_per_table = 1

2. Для "проблемной" таблицы выполнить команду

ALTER TABLE tableName ENGINE = InnoDB ROW_FORMAT = Dynamic;

Но это еще не все. Чтобы изменения вступили в силу, необходимо сделать дамп таблицы, удалить ее, а потом заново создать таблицу из дампа, который вы создали.