Изменить предел для "Mysql Row size too large"

Как я могу изменить лимит

Слишком большой размер строки (> 8126). Изменение некоторых столбцов на TEXT или BLOB или использование ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED может помочь В текущем формате строки, BLOB префикс 768 байт хранится в строке.

Таблица:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 

19 ответов

Вопрос был задан и на сервере.

Возможно, вы захотите взглянуть на эту статью, которая многое объясняет о размерах строк MySQL. Важно отметить, что даже если вы используете поля TEXT или BLOB, размер строки может быть больше 8 КБ (предел для InnoDB), поскольку он хранит первые 768 байт для каждого встроенного поля на странице.

Самый простой способ исправить это - использовать формат файла Barracuda с InnoDB. Это в основном полностью избавляет от проблемы, сохраняя только 20-байтовый указатель на текстовые данные вместо того, чтобы сохранять первые 768 байт.


Метод, который работал для ОП там был:

  1. Добавьте следующее к my.cnf файл под [mysqld] раздел.

    innodb_file_per_table=1
    innodb_file_format = Barracuda
    
  2. ALTER стол для использования ROW_FORMAT=COMPRESSED,

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;
    

Существует вероятность того, что вышеуказанное все еще не решит ваши проблемы. Это известная (и проверенная) ошибка в механизме InnoDB, и на данный момент временное исправление - откат к механизму MyISAM в качестве временного хранилища. Итак, в вашем my.cnf файл:

internal_tmp_disk_storage_engine=MyISAM

Недавно я столкнулся с этой проблемой и решил ее по-другому. Если вы используете MySQL версии 5.6.20, в системе есть известная ошибка. Смотрите документы MySQL

Внимание! Из-за ошибки #69477 записи журнала повторов для больших, сохраненных извне полей BLOB могут перезаписать самую последнюю контрольную точку. Чтобы устранить эту ошибку, исправление, введенное в MySQL 5.6.20, ограничивает размер записи журнала BLOB повторов в 10% от размера файла журнала повторов. В результате этого ограничения для innodb_log_file_size должно быть установлено значение, в 10 раз превышающее максимальный размер данных BLOB, найденный в строках ваших таблиц, плюс длина других полей переменной длины (поля типов VARCHAR, VARBINARY и TEXT).

В моей ситуации таблица блобов-нарушителей составляла около 16 МБ. Таким образом, я решил это, добавив строку в my.cnf, которая гарантировала, что у меня будет как минимум 10-кратное количество, а затем немного:

innodb_log_file_size = 256M

Установите следующие параметры в файле my.cnf и перезапустите сервер MySQL.

innodb_strict_mode = 0

Если вы можете переключить ДВИГАТЕЛЬ и использовать MyISAM вместо InnoDB, это должно помочь:

ENGINE=MyISAM

Есть два предостережения с MyISAM (возможно, больше):

  1. Вы не можете использовать транзакции.
  2. Вы не можете использовать ограничения внешнего ключа.

У меня была та же проблема, это решило ее для меня:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

Из документации MYSQL:

Формат строки DYNAMIC поддерживает эффективность сохранения всей строки в узле индекса, если он подходит (как это делают форматы COMPACT и REDUNDANT), но этот новый формат устраняет проблему заполнения узлов B-дерева большим количеством байтов данных длинные колонны. Формат DYNAMIC основан на идее, что, если часть длинного значения данных хранится вне страницы, обычно наиболее эффективно хранить все значения вне страницы. В формате DYNAMIC более короткие столбцы, скорее всего, останутся в узле B-дерева, минимизируя количество страниц переполнения, необходимых для любой данной строки.

Я хотел бы поделиться удивительным ответом, это может быть полезно. Кредиты Билла Карвина смотрите здесь https://dba.stackexchange.com/questions/6598/innodb-create-table-error-row-size-too-large

Они различаются в зависимости от формата файла InnoDB. В настоящее время существует 2 формата, называемых Antelope и Barracuda.

Центральный файл табличного пространства (ibdata1) всегда имеет формат антилопы. Если вы используете файл для каждой таблицы, вы можете настроить отдельные файлы в формате Barracuda, установив innodb_file_format=Barracuda в my.cnf.

Основные моменты:

  1. Одна страница размером 16 КБ данных InnoDB должна содержать как минимум две строки данных. Кроме того, каждая страница имеет верхний и нижний колонтитулы, содержащие контрольные суммы страниц и порядковый номер журнала и так далее. Вот где вы получите свой предел чуть менее 8 КБ на строку.

  2. Типы данных фиксированного размера, такие как INTEGER, DATE, FLOAT, CHAR, хранятся на этой первичной странице данных и учитываются в пределе размера строки.

  3. Типы данных переменного размера, такие как VARCHAR, TEXT, BLOB, хранятся на страницах переполнения, поэтому они не учитываются полностью до предела размера строки. В антилопе до 768 байт таких столбцов хранятся на первичной странице данных в дополнение к хранению на странице переполнения. Barracuda поддерживает динамический формат строки, поэтому он может хранить только 20-байтовый указатель на первичной странице данных.

  4. Типы данных переменного размера также имеют префикс 1 или более байтов для кодирования длины. И формат строки InnoDB также имеет массив смещений полей. Так что внутренняя структура более или менее задокументирована в их вики.

Barracuda также поддерживает ROW_FORMAT=COMPRESSED для повышения эффективности хранения данных переполнения.

Я также должен отметить, что я никогда не видел, чтобы хорошо спроектированная таблица превышала предел размера строки. Это сильный "кодовый запах", что вы нарушаете условие повторяющихся групп в первой нормальной форме.

Вам нужно внести некоторые изменения в my.ini файл

Добавьте это в [mysqld]

innodb_strict_mode=0

Обновите эти две строки

innodb_log_file_size=256M
innodb_log_buffer_size=256M

innodb_strict_mode: Когда он включен, определенные предупреждения InnoDB вместо этого становятся ошибками.

Ссылка: https://mariadb.com/kb/en/innodb-strict-mode/

innodb_log_file_size & innodb_log_buffer_size нужно увеличивать в размерах.

Потратив часы, я нашел решение: просто запустите следующий SQL в вашем администраторе MySQL, чтобы преобразовать таблицу в MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;

Максимальный размер строки для таблицы InnoDB, которая применяется к данным, хранящимся локально на странице базы данных, составляет чуть меньше половины страницы для 4 КБ, 8 КБ, 16 КБ и 32 КБ.

Для страниц размером 16 КБ (по умолчанию) мы можем рассчитать:

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

В принципе, вы можете максимально увеличить строку с помощью:

  • 11 полей varchar> 767 символов (latin1 = 1 байт на символ) или
  • 11 полей varchar> 255 символов (utf-8 для mysql = 3 байта на символ).

Помните, что переполнение произойдет только в том случае, если размер поля> 767 байт. Если имеется слишком много полей размером 767 байт, оно будет отключено (превышение максимального размера строки). Не обычно с latin1, но вполне возможно с utf-8, если разработчики не будут осторожны.

В этом случае, я думаю, вы могли бы увеличить innodb_page_size до 32 КБ.

в my.cnf:

innodb_page_size=32K

Ссылки:

Я использую MySQL 5.6 на AWS RDS. Я обновил следующее в группе параметров.

innodb_file_per_table=1
innodb_file_format = Barracuda

Мне пришлось перезагрузить экземпляр БД, чтобы изменения группы параметров вступили в силу.

Кроме того, ROW_FORMAT=COMPRESSED не поддерживался. Я использовал DYNAMIC, как показано ниже, и он работал нормально.

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8

Я столкнулся с этой проблемой, когда пытался восстановить резервную копию базы данных mysql с другого сервера. Что решило эту проблему для меня, так это добавив определенные настройки в my.conf (как в приведенных выше вопросах) и дополнительно изменив файл резервной копии sql:

Шаг 1: добавьте или отредактируйте следующие строки в my.conf:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

Шаг 2 добавьте ROW_FORMAT=DYNAMIC в оператор создания таблицы в файле резервной копии sql для таблицы, которая вызывает эту ошибку:

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

важное изменение, приведенное выше, это ROW_FORMAT=DYNAMIC; (это не было включено в файл резервной копии оригинального sql)

источник, который помог мне решить эту проблему: слишком большой размер MariaDB и InnoDB MySQL Row

Другие ответы относятся к заданному вопросу. Я рассмотрю основную причину: плохой дизайн схемы.

Не распределяйте массив по столбцам. Здесь у вас есть 3*10 столбцов, которые должны быть превращены в 10 строк по 3 столбца в новой таблице (плюс id, так далее)

Ваш Main стол будет иметь только

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

Ваш дополнительный стол (Top) будет иметь

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

Там будет 10 (или меньше? Или больше?) Строк в Top для каждого id,

Это устраняет вашу первоначальную проблему и очищает схему. (Это не "нормализация", как обсуждается в некоторых комментариях.)

Не переключайтесь на MyISAM; это уходит.
Не беспокойся о ROW_FORMAT,

Вам нужно будет изменить свой код, чтобы сделать JOIN и обрабатывать несколько строк вместо нескольких столбцов.

Я продолжаю сталкиваться с этой проблемой, когда уничтожаю свой ящик Laravel Homestead (Vagrant) и начинаю заново.

  1. SSH в поле из командной строки homestead ssh

  2. Заходим в файл my.cnf sudo vi /etc/mysql/my.cnf

  3. Добавьте следующие строки в конец файла (под! Includedir)

    [mysqld]

    innodb_log_file_size=512M

    innodb_strict_mode=0

  4. Сохраните изменения в my.cnf, затем перезагрузите MYSQL sudo service mysql restart

Чтобы решить эту проблему, вам нужно изменить innodb на myisam в вашем phpmyadmin. Посмотри на эту картинку.

Для MariaDB эта проблема решается увеличением значения с 16k до 32k в файле my.ini.

      innodb_page_size=32K

который в моем случае находится по адресу D:\wamp\bin\mariadb\mariadb10.6.5 .

Вот простой совет для всех, кто интересуется:

После обновления с Debian 9 до Debian 10 с помощью 10.3.17-MariaDB у меня возникли ошибки в базах данных Joomla:

[Предупреждение] InnoDB: невозможно добавить поле field в таблице database.table потому что после его добавления размер строки составляет 8742, что превышает максимально допустимый размер (8126) для записи на конечной странице индекса.

На всякий случай я установил innodb_default_row_format = DYNAMIC в /etc/mysql/mariadb.conf.d/50-server.cnf (все равно было по умолчанию)

Затем я использовал phpmyadmin для запуска "Оптимизации таблицы" для всех таблиц в базе данных Joomla. Я думаю, что воссоздание таблицы, выполненное phpmyadmin, помогло. Если у вас установлен phpmyadmin, достаточно сделать несколько кликов.

В Mysql 5.6 :

Выполните следующие SQL-КОМАНДЫ:

      Mysql > SET GLOBAL innodb_file_format=Barracuda; 
Mysql > ALTER TABLE `name_of_my_table_here` ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8; 

Я также столкнулся с той же проблемой. Я решаю проблему, выполнив следующий sql:

ALTER ${table} ROW_FORMAT=COMPRESSED;

Но я думаю, вы должны знать о хранении строк.
Существует два вида столбцов: столбец переменной длины(например, типы VARCHAR, VARBINARY, BLOB и TEXT) и столбец фиксированной длины. Они хранятся на разных типах страниц.

Столбцы переменной длины являются исключением из этого правила. Столбцы, такие как BLOB и VARCHAR, которые слишком длинны для размещения на странице B-дерева, хранятся на отдельно выделенных страницах диска, называемых страницами переполнения. Мы называем такие столбцы внестраничными столбцами. Значения этих столбцов хранятся в односвязных списках страниц переполнения, и каждый такой столбец имеет свой собственный список из одной или нескольких страниц переполнения. В некоторых случаях весь или префикс значения длинного столбца хранится в B-дереве, чтобы избежать потери памяти и избавления от необходимости читать отдельную страницу.

и когда целью установки ROW_FORMAT является

Когда таблица создается с ROW_FORMAT=DYNAMIC или ROW_FORMAT=COMPRESSED, InnoDB может хранить длинные значения столбцов переменной длины (для типов VARCHAR, VARBINARY, и BLOB и TEXT) полностью вне страницы, причем запись кластеризованного индекса, содержащая только 20- байтовый указатель на страницу переполнения.

Хотите узнать больше о динамических и сжатых форматах строк

Если это происходит в SELECT с большим количеством столбцов, причиной может быть то, что mysql создает временную таблицу. Если эта таблица слишком велика для размещения в памяти, она будет использовать свой формат временной таблицы по умолчанию, которым является InnoDB, для хранения ее на Диске. В этом случае применяются ограничения размера InnoDB.

Затем у вас есть 4 варианта:

  1. измените ограничение размера строки innodb, как указано в другом сообщении, что требует повторной инициализации сервера.
  2. измените свой запрос, чтобы он включал меньше столбцов или не заставлял его создавать временную таблицу (например, удалив предложения order by и limit).
  3. изменение max_heap_table_size на большой, чтобы результат умещался в памяти и не нужно было записывать на диск.
  4. измените формат временной таблицы по умолчанию на MYISAM, вот что я сделал. Изменение в my.cnf:

    internal_tmp_disk_storage_engine=MYISAM
    

Перезапустите mysql, запрос работает.

Другие вопросы по тегам