Изменить предел для "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 байт.
Метод, который работал для ОП там был:
Добавьте следующее к
my.cnf
файл под[mysqld]
раздел.innodb_file_per_table=1 innodb_file_format = Barracuda
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 (возможно, больше):
- Вы не можете использовать транзакции.
- Вы не можете использовать ограничения внешнего ключа.
У меня была та же проблема, это решило ее для меня:
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.
Основные моменты:
Одна страница размером 16 КБ данных InnoDB должна содержать как минимум две строки данных. Кроме того, каждая страница имеет верхний и нижний колонтитулы, содержащие контрольные суммы страниц и порядковый номер журнала и так далее. Вот где вы получите свой предел чуть менее 8 КБ на строку.
Типы данных фиксированного размера, такие как INTEGER, DATE, FLOAT, CHAR, хранятся на этой первичной странице данных и учитываются в пределе размера строки.
Типы данных переменного размера, такие как VARCHAR, TEXT, BLOB, хранятся на страницах переполнения, поэтому они не учитываются полностью до предела размера строки. В антилопе до 768 байт таких столбцов хранятся на первичной странице данных в дополнение к хранению на странице переполнения. Barracuda поддерживает динамический формат строки, поэтому он может хранить только 20-байтовый указатель на первичной странице данных.
Типы данных переменного размера также имеют префикс 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) и начинаю заново.
SSH в поле из командной строки
homestead ssh
Заходим в файл my.cnf
sudo vi /etc/mysql/my.cnf
Добавьте следующие строки в конец файла (под! Includedir)
[mysqld]
innodb_log_file_size=512M
innodb_strict_mode=0
Сохраните изменения в 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 варианта:
- измените ограничение размера строки innodb, как указано в другом сообщении, что требует повторной инициализации сервера.
- измените свой запрос, чтобы он включал меньше столбцов или не заставлял его создавать временную таблицу (например, удалив предложения order by и limit).
- изменение max_heap_table_size на большой, чтобы результат умещался в памяти и не нужно было записывать на диск.
измените формат временной таблицы по умолчанию на MYISAM, вот что я сделал. Изменение в my.cnf:
internal_tmp_disk_storage_engine=MYISAM
Перезапустите mysql, запрос работает.