Измените ограничение для «Размер строки Mysql слишком велик»

106

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

Размер строки слишком велик (> 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 
Лаша Курт
источник
1
Что Noотображается?
hjpotter92
Не удается обновить ошибку «Размер строки слишком велик (> 8126). Изменение некоторых столбцов на TEXT или BLOB или использование ROW_FORMAT = DYNAMIC или ROW_FORMAT = COMPRESSED может помочь. В текущем формате строки префикс BLOB размером 768 байт хранится в строке».
Лаша Курт
Можете ли вы добавить к своему сообщению какие-то другие детали, хотя бы в качестве комментария?
Eineki
1
если эти данные находятся в другой таблице, рассмотрите возможность использования вместо этого внешнего ключа, это резко уменьшит размер вашей строки и нормализует схему вашей базы данных.
didierc
1
@AL: Ой, вы правы - проголосуйте внимательно за другого
pathikrit

Ответы:

122

Вопрос задан и по serverfault .

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

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


Метод, который работал для OP, был:

  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
hjpotter92
источник
12
+1 -> Часть innodb_file_per_table имеет решающее значение и идет рука об руку с изменением формата на Barracuda. Без этого MySQL продолжит молча использовать Antelope.
Ник
1
@Eduardo Я бы порекомендовал сначала сделать резервную копию данных. Но да, вы можете сделать это и на производстве!
hjpotter92 03
3
Используйте, innodb_file_per_table=1чтобы активировать эту опцию.
Stijn Geukens
2
Это не гарантирует устранения проблемы. В этом посте приведен пример сценария, который добавляет эти настройки, но все еще может воспроизвести ошибку.
Cerin
1
@ user1183352 Обновил мой ответ выше. Спасибо, что снова напомнили мне, чтобы я погрузился в это глубже. :)
hjpotter92 01
62

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

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

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

innodb_log_file_size = 256M

Колин
источник
Пятно на. Моя ошибка «Слишком большой размер строки» в longblobполе исчезла, как только я увеличил innodb_log_file_sizeпараметр. Также была запущена 5.6.20.
adamup
Спасибо. Был запущен homebrew 5.6.21, изменение параметра устранило проблему.
nanoman
И этот, и ответ @ hjpotter92 потребовались, чтобы исправить эту ошибку для меня.
Cerin
Спасибо. Была запущена версия 5.6.21, и это решение помогло.
Петяр
Это тоже не решило мою проблему. Я подумываю о замене многих полей VARCHAR на TEXT, как я видел в аналогичных потоках.
PDoria 01
29

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

innodb_strict_mode=0
Карл
источник
2
innodb_strict_mode=0-> без пробелов. В противном случае перезапуск mariaDB 10.2 приведет к ошибке :-P
Pathros
Я не пробовал с mariadb, для MySQL не нужно удалять пробелы.
Карл
1
Согласно документации, отключение строгого режима только предотвращает появление ошибок и предупреждений, так что, похоже, это не решает проблему! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
Жоао Тейшейра,
2
Кажется, это работает, и я могу без проблем создавать таблицы и сохранять данные
Крис Мюнч,
@ João, это больше ... dev.mysql.com/doc/refman/8.0/en/…
Карл
23

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

ENGINE=MyISAM

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

  1. Вы не можете использовать транзакции.
  2. Вы не можете использовать ограничения внешнего ключа.
Феникс
источник
6
Хорошо, если вы не против обходиться без транзакций и ограничений внешнего ключа. Но имейте в виду, что вы теряете их при переходе на MyISAM.
wobbily_col
1
Этот совет безумный - по крайней мере, он будет содержать все предостережения! Транзакции и ограничения на ключевые слова - наименьшая из проблем этого формата!
Хасан Сайед,
К сожалению, проголосовал против этого ответа. Пожалуйста, обновите, чтобы упомянуть все возможные предостережения. Любой, кто следует этому совету, переключается на формат, который я бы никогда не использовал ни в одной производственной системе.
Remco Wendt
2
И MyISAM уходит.
Рик Джеймс
2
работал у меня. В моем случае у меня было более 300 полей длиной около 10 каждое. У меня нет никаких взаимосвязей в этой таблице, поэтому переход на MyISAM был исправлением.
Роберт
13

Хочу поделиться классным ответом, может быть, полезно. Кредиты Билла Карвина смотрите здесь /dba/6598/innodb-create-table-error-row-size-too-large

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

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

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

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

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

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

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

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

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

Аман Чхабра
источник
8

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

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

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

Формат строки DYNAMIC поддерживает эффективность хранения всей строки в индексном узле, если он подходит (как и форматы COMPACT и REDUNDANT), но этот новый формат позволяет избежать проблемы заполнения узлов B-дерева большим количеством байтов данных. длинные колонны. Формат DYNAMIC основан на идее, что если часть длинного значения данных хранится вне страницы, обычно наиболее эффективно хранить все значение вне страницы. При использовании ДИНАМИЧЕСКОГО формата более короткие столбцы, вероятно, останутся в узле B-дерева, что минимизирует количество страниц переполнения, необходимых для любой данной строки.

multimediaxp
источник
... но вам нужен другой формат файла, значит, вы уже используете Barracuda? Потому что я получаю сообщение об ошибке при выполнении этой команды, говоряWarnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Тед
Когда я позволил HeidiSQL выполнить ту же команду через встроенный графический интерфейс, это каким-то образом преуспело, но это не помогло вообще, я получаю ту же ошибку,Row size too large (>8126)
Тед
Попробуйте установить innodb_file_format = Barracuda в my.ini и попробуйте ALTER TABLE my_tableROW_FORMAT = DYNAMIC; снова
multimediaxp
Да, я думаю, что именно это я и сделал в конце концов, и я думаю, что это решило проблему. Но я также в отчаянии одновременно изменил множество столбцов на ТЕКСТ =) Спасибо, хотя, на самом деле, я думаю, что это все.
Тед
Хорошо !, если вы считаете, что это хороший ответ, проголосуйте за него и примите его как действительный ответ, спасибо!
multimediaxp
5

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

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
Ифтихар Хан
источник
Не очень помогает, если проблема возникает в операторе создания таблицы.
Марк Фрейзер
create tableесть такой же вариант:CREATE TABLE ... ENGINE=MyISAM ...
xebeche
3

Я столкнулся с этой проблемой, когда пытался восстановить резервную копию базы данных 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 size слишком большой

Матиас
источник
2
Строки, описанные в шаге 1, не должны иметь пробелов. Строка innodb_page_size=32Kне сработала, так как в моем случае это вызвало ошибку при перезапуске MariaDB 10.2. Вместо этого я добавил innodb_strict_mode=0строку, как описано здесь
Pathros
1
спасибо за отзыв, Патрос, я обновил свой ответ и удалил пробелы с шага 1.
matyas
Примечание для MySQL <= 5.7.5: 32K не является допустимой опцией для innodb_page_size. См .: dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar
Кроме того, вы должны воссоздать весь свой сервер mysql для scracth, так как изменение innodb_page_sizeтребует ibdata*воссоздания, что является разрушительной операцией. Смотрите системный журнал для получения дополнительной информации
Матия Налис
2

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

Не размещайте массив по столбцам. Здесь у вас есть 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

Для Topкаждого должно быть 10 (или меньше? Или больше?) Строк id.

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

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

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

Рик Джеймс
источник
1

Я использую 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
Михир Каграна
источник
1

Максимальный размер строки для таблицы 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

Ссылки:

U0001
источник
0

Я тоже столкнулся с той же проблемой. Решаю проблему, выполнив следующий 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- байтовый указатель на страницу переполнения.

Хотите узнать больше о ДИНАМИЧЕСКИХ и СЖАТЫХ форматах строк

Будет
источник
0

Если это происходит в 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, запрос работает.

бхельм
источник
0

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

После обновления с 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, достаточно сделать несколько кликов.

Joomlauser
источник
Если вы являетесь пользователем Joomla, присоединяйтесь к нам на Joomla Stack Exchange - мы всегда можем использовать новых участников.
mickmackusa