Исправляем ошибку MySQL «Row size too large» в 1с-Битрикс

Если Вы используете в своих проектах инфоблоки 2.0 и таблицы InnoDB, то есть шанс в один прекрасный момент столкнуться с ошибкой MySQL «SQL Error (1118): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs» (или «Got error 139 from storage engine»). Ниже рассмотрены причины и условия ее возникновения, а также различные методы устранения, с вмешательством в настройки сервера или без него.

Причины

Данная ошибка возникает в таблицах InnoDB при попытке чтения строки с большим количеством заполненных текстовых полей. Сумма длин всех текстовых полей (но не более 768 байтов каждого поля) не должна превышать половины страницы памяти, которая указана в настройках MySQL. В моем случае это было 16кб, отсюда и цифра 8126 байт в названии ошибки.

Условия возникновения в 1с-Битрикс

К ошибке приводит совокупность факторов:
- использование инфоблоков 2.0, т.е. хранение свойств в отдельных таблицах;
- MySQL в качестве сервера базы данных;
- тип InnoDB для таблицы свойств инфоблока;
- большое количество свойств строкового типа. Точная цифра зависит от настроек сервера.

Методы решения

Условно решения можно разделить на 2 группы — с необходимостью правки конфигурации сервера и без нее. Все советы даны применительно к битриксу. Естественно перед экспериментами нужно сделать резервную копию.

Без правки конфигурации:

1. Перевести таблицу в MyISAM. В моем случае это вызвало 2 проблемы — битрикс неправильно конвертировал заполненные значения свойств и при первом добавлении элемента инфоблока пропали половина свойств других элементов. Почему именно так получилось не ясно, но факт остается фактом — риск поломать таблицу есть.

2. Вернуться на инфоблоки 1.0. В этом случае каждое свойство будет храниться в отдельной строке общей таблицы, строка «влезет» в отведенную ей память и ошибка пропадет. Метод не всегда применим, потому что есть некоторые различия в форматах объектов, возвращаемых функцией CIBlockElement::GetList(), и в некоторых случаях придется переписывать код.

С вмешательством в настройки сервера:

1. Увеличить размер страницы памяти. Для этого в файле univ.i установить значения

#define UNIV_PAGE_SIZE (8 * 8192) 
#define UNIV_PAGE_SIZE_SHIFT 16

и пересобрать MySQL.

Минусы подхода хорошо описаны в этой статье.

2. Для MySQL версии > 5.5 изменить формат таблиц на DYNAMIC

ALTER TABLE tableName ENGINE = InnoDB ROW_FORMAT = Dynamic;

Для MySQL версии > 5.0 нужно сначала подключить InnoDB через плагин, поддерживающий формат файлов barracuda.

Хостинг TimeWeb точно подвержен этой ошибке. Будьте внимательны и заранее продумывайте архитектуру проекта.

В заключение, несколько полезных ссылок по теме:
8123 байта хватит каждому
Инфоблоки+ и «Got error 139 from storage engine»
Blob Storage in Innodb

Если вам понравилась статья, подписывайтесь на обновления блога по rss или присоединяйтесь в twitter

Поделиться ссылкой с друзьями:

Метки: ,

Категории: Bitrix

Комментарии (3)

  1. У меня была такая проблема на одном из сайтов, но тип таблиц был MyISAM, перевод в InnoDB ничего не изменил, так что тип таблицы здесь ни при чем.

    Дело действительно в режиме хранения свойств, помог перевод инфоблока обратно в инфоблоки 1.0

    Спасибо за наводку!

  2. Маленький хак.
    Если нужно добавить в инфоблок всего пару-тройку свойств, то можно просто для некоторых свойств сменить тип данных у столбцов DESCRIPTION_ с VARCHAR(255) на TEXT в таблице b_iblock_element_prop_s.
    Если описания значений не используются совсем, то таким образом можно увеличить максимальное количество свойств где-то до 500 — то есть упираемся уже в другое ограничение таблиц InnoDB — максимально 1000 столбцов (http://dev.mysql.com/doc/refman/5.0/en/column-count-limit.html).

  3. Блин, парсер съел текст…
    DESCRIPTION_[PROPERTY_ID] и b_iblock_element_prop_s[IBLOCK_ID]